[flang] typed function references
authorpeter klausler <pklausler@nvidia.com>
Thu, 20 Sep 2018 19:34:29 +0000 (12:34 -0700)
committerpeter klausler <pklausler@nvidia.com>
Tue, 25 Sep 2018 22:24:04 +0000 (15:24 -0700)
Original-commit: flang-compiler/f18@e9b9d729580d3ec909d8108d8191157e2cc1d4db
Reviewed-on: https://github.com/flang-compiler/f18/pull/195
Tree-same-pre-rewrite: false

flang/lib/evaluate/expression.cc
flang/lib/evaluate/expression.h
flang/lib/evaluate/type.h
flang/lib/evaluate/variable.cc
flang/lib/evaluate/variable.h
flang/lib/semantics/expression.cc

index 84fc817d4db65143a65789c372229281fa4f0d4b..983d555768dca45f1d77bd0a92b8b86c253b3fd3 100644 (file)
@@ -463,23 +463,11 @@ template<typename T> std::ostream &Constant<T>::Dump(std::ostream &o) const {
 
 template<typename RESULT>
 std::ostream &ExpressionBase<RESULT>::Dump(std::ostream &o) const {
-  std::visit(
-      common::visitors{[&](const BOZLiteralConstant &x) {
-                         o << "Z'" << x.Hexadecimal() << "'";
-                       },
-          [&](const CopyableIndirection<Substring> &s) { s->Dump(o); },
-          [&](const auto &x) {
-            if constexpr (Result::isSpecificType) {
-              using Ty = std::decay_t<decltype(x)>;
-              if constexpr (std::is_same_v<Ty, FunctionReference<Result>>) {
-                x.reference->Dump(o);
-              } else {
-                x.Dump(o);
-              }
-            } else {
-              x.Dump(o);
-            }
-          }},
+  std::visit(common::visitors{[&](const BOZLiteralConstant &x) {
+                                o << "Z'" << x.Hexadecimal() << "'";
+                              },
+                 [&](const CopyableIndirection<Substring> &s) { s->Dump(o); },
+                 [&](const auto &x) { x.Dump(o); }},
       derived().u);
   return o;
 }
@@ -502,9 +490,7 @@ Expr<SubscriptInteger> Expr<Type<TypeCategory::Character, KIND>>::LEN() const {
                 Extremum<SubscriptInteger>{c.left().LEN(), c.right().LEN()}};
           },
           [](const Designator<Result> &dr) { return dr.LEN(); },
-          [](const FunctionReference<Result> &fr) {
-            return fr.reference->proc().LEN();
-          }},
+          [](const FunctionRef<Result> &fr) { return fr.LEN(); }},
       u);
 }
 
@@ -561,78 +547,13 @@ template<typename A> int ExpressionBase<A>::Rank() const {
 // Template instantiations to resolve the "extern template" declarations
 // that appear in expression.h.
 
-template class Expr<Type<TypeCategory::Integer, 1>>;
-template class Expr<Type<TypeCategory::Integer, 2>>;
-template class Expr<Type<TypeCategory::Integer, 4>>;
-template class Expr<Type<TypeCategory::Integer, 8>>;
-template class Expr<Type<TypeCategory::Integer, 16>>;
-template class Expr<Type<TypeCategory::Real, 2>>;
-template class Expr<Type<TypeCategory::Real, 4>>;
-template class Expr<Type<TypeCategory::Real, 8>>;
-template class Expr<Type<TypeCategory::Real, 10>>;
-template class Expr<Type<TypeCategory::Real, 16>>;
-template class Expr<Type<TypeCategory::Complex, 2>>;
-template class Expr<Type<TypeCategory::Complex, 4>>;
-template class Expr<Type<TypeCategory::Complex, 8>>;
-template class Expr<Type<TypeCategory::Complex, 10>>;
-template class Expr<Type<TypeCategory::Complex, 16>>;
-template class Expr<Type<TypeCategory::Character, 1>>;
-template class Expr<Type<TypeCategory::Character, 2>>;
-template class Expr<Type<TypeCategory::Character, 4>>;
-template class Expr<Type<TypeCategory::Logical, 1>>;
-template class Expr<Type<TypeCategory::Logical, 2>>;
-template class Expr<Type<TypeCategory::Logical, 4>>;
-template class Expr<Type<TypeCategory::Logical, 8>>;
-template class Expr<SomeInteger>;
-template class Expr<SomeReal>;
-template class Expr<SomeComplex>;
-template class Expr<SomeCharacter>;
-template class Expr<SomeLogical>;
-template class Expr<SomeType>;
-
-template struct Relational<Type<TypeCategory::Integer, 1>>;
-template struct Relational<Type<TypeCategory::Integer, 2>>;
-template struct Relational<Type<TypeCategory::Integer, 4>>;
-template struct Relational<Type<TypeCategory::Integer, 8>>;
-template struct Relational<Type<TypeCategory::Integer, 16>>;
-template struct Relational<Type<TypeCategory::Real, 2>>;
-template struct Relational<Type<TypeCategory::Real, 4>>;
-template struct Relational<Type<TypeCategory::Real, 8>>;
-template struct Relational<Type<TypeCategory::Real, 10>>;
-template struct Relational<Type<TypeCategory::Real, 16>>;
-template struct Relational<Type<TypeCategory::Character, 1>>;
-template struct Relational<Type<TypeCategory::Character, 2>>;
-template struct Relational<Type<TypeCategory::Character, 4>>;
+FOR_EACH_TYPE_AND_KIND(template class Expr)
+FOR_EACH_INTEGER_KIND(template struct Relational)
+FOR_EACH_REAL_KIND(template struct Relational)
+FOR_EACH_CHARACTER_KIND(template struct Relational)
 template struct Relational<SomeType>;
-
-template struct ExpressionBase<Type<TypeCategory::Integer, 1>>;
-template struct ExpressionBase<Type<TypeCategory::Integer, 2>>;
-template struct ExpressionBase<Type<TypeCategory::Integer, 4>>;
-template struct ExpressionBase<Type<TypeCategory::Integer, 8>>;
-template struct ExpressionBase<Type<TypeCategory::Integer, 16>>;
-template struct ExpressionBase<Type<TypeCategory::Real, 2>>;
-template struct ExpressionBase<Type<TypeCategory::Real, 4>>;
-template struct ExpressionBase<Type<TypeCategory::Real, 8>>;
-template struct ExpressionBase<Type<TypeCategory::Real, 10>>;
-template struct ExpressionBase<Type<TypeCategory::Real, 16>>;
-template struct ExpressionBase<Type<TypeCategory::Complex, 2>>;
-template struct ExpressionBase<Type<TypeCategory::Complex, 4>>;
-template struct ExpressionBase<Type<TypeCategory::Complex, 8>>;
-template struct ExpressionBase<Type<TypeCategory::Complex, 10>>;
-template struct ExpressionBase<Type<TypeCategory::Complex, 16>>;
-template struct ExpressionBase<Type<TypeCategory::Character, 1>>;
-template struct ExpressionBase<Type<TypeCategory::Character, 2>>;
-template struct ExpressionBase<Type<TypeCategory::Character, 4>>;
-template struct ExpressionBase<Type<TypeCategory::Logical, 1>>;
-template struct ExpressionBase<Type<TypeCategory::Logical, 2>>;
-template struct ExpressionBase<Type<TypeCategory::Logical, 4>>;
-template struct ExpressionBase<Type<TypeCategory::Logical, 8>>;
-template struct ExpressionBase<SomeInteger>;
-template struct ExpressionBase<SomeReal>;
-template struct ExpressionBase<SomeComplex>;
-template struct ExpressionBase<SomeCharacter>;
-template struct ExpressionBase<SomeLogical>;
-template struct ExpressionBase<SomeType>;
+FOR_EACH_INTRINSIC_KIND(template struct ExpressionBase)
+FOR_EACH_CATEGORY_TYPE(template struct ExpressionBase)
 
 }  // namespace Fortran::evaluate
 
index a04a1285a90efad822157da8d6879e562ccc3fd6..1276386236c2dd509f88453c09865b118c563b38 100644 (file)
@@ -78,13 +78,6 @@ template<typename T> struct Constant {
 // to be used in only a few situations.
 using BOZLiteralConstant = typename LargestReal::Scalar::Word;
 
-template<typename T> struct FunctionReference {
-  using Result = T;
-  static_assert(Result::isSpecificType);
-  int Rank() const { return reference->Rank(); }
-  CopyableIndirection<FunctionRef> reference;
-};
-
 // Operations always have specific Fortran result types (i.e., with known
 // intrinsic type category and kind parameter value).  The classes that
 // represent the operations all inherit from this Operation<> base class
@@ -449,8 +442,8 @@ private:
   using Operations = std::variant<Parentheses<Result>, Negate<Result>,
       Add<Result>, Subtract<Result>, Multiply<Result>, Divide<Result>,
       Power<Result>, Extremum<Result>>;
-  using Others = std::variant<Constant<Result>, Designator<Result>,
-      FunctionReference<Result>>;
+  using Others =
+      std::variant<Constant<Result>, Designator<Result>, FunctionRef<Result>>;
 
 public:
   common::CombineVariants<Operations, Conversions, Others> u;
@@ -475,8 +468,8 @@ private:
   using Operations = std::variant<ComplexComponent<KIND>, Parentheses<Result>,
       Negate<Result>, Add<Result>, Subtract<Result>, Multiply<Result>,
       Divide<Result>, Power<Result>, RealToIntPower<Result>, Extremum<Result>>;
-  using Others = std::variant<Constant<Result>, Designator<Result>,
-      FunctionReference<Result>>;
+  using Others =
+      std::variant<Constant<Result>, Designator<Result>, FunctionRef<Result>>;
 
 public:
   common::CombineVariants<Operations, Conversions, Others> u;
@@ -496,28 +489,16 @@ public:
   using Operations =
       std::variant<Parentheses<Result>, Multiply<Result>, Divide<Result>,
           Power<Result>, RealToIntPower<Result>, ComplexConstructor<KIND>>;
-  using Others = std::variant<Constant<Result>, Designator<Result>,
-      FunctionReference<Result>>;
+  using Others =
+      std::variant<Constant<Result>, Designator<Result>, FunctionRef<Result>>;
 
 public:
   common::CombineVariants<Operations, Others> u;
 };
 
-extern template class Expr<Type<TypeCategory::Integer, 1>>;
-extern template class Expr<Type<TypeCategory::Integer, 2>>;
-extern template class Expr<Type<TypeCategory::Integer, 4>>;
-extern template class Expr<Type<TypeCategory::Integer, 8>>;
-extern template class Expr<Type<TypeCategory::Integer, 16>>;
-extern template class Expr<Type<TypeCategory::Real, 2>>;
-extern template class Expr<Type<TypeCategory::Real, 4>>;
-extern template class Expr<Type<TypeCategory::Real, 8>>;
-extern template class Expr<Type<TypeCategory::Real, 10>>;
-extern template class Expr<Type<TypeCategory::Real, 16>>;
-extern template class Expr<Type<TypeCategory::Complex, 2>>;
-extern template class Expr<Type<TypeCategory::Complex, 4>>;
-extern template class Expr<Type<TypeCategory::Complex, 8>>;
-extern template class Expr<Type<TypeCategory::Complex, 10>>;
-extern template class Expr<Type<TypeCategory::Complex, 16>>;
+FOR_EACH_INTEGER_KIND(extern template class Expr)
+FOR_EACH_REAL_KIND(extern template class Expr)
+FOR_EACH_COMPLEX_KIND(extern template class Expr)
 
 template<int KIND>
 class Expr<Type<TypeCategory::Character, KIND>>
@@ -531,14 +512,12 @@ public:
 
   Expr<SubscriptInteger> LEN() const;
 
-  std::variant<Constant<Result>, Designator<Result>, FunctionReference<Result>,
+  std::variant<Constant<Result>, Designator<Result>, FunctionRef<Result>,
       Parentheses<Result>, Concat<KIND>, Extremum<Result>>
       u;
 };
 
-extern template class Expr<Type<TypeCategory::Character, 1>>;
-extern template class Expr<Type<TypeCategory::Character, 2>>;
-extern template class Expr<Type<TypeCategory::Character, 4>>;
+FOR_EACH_CHARACTER_KIND(extern template class Expr)
 
 // The Relational class template is a helper for constructing logical
 // expressions with polymorphism over the cross product of the possible
@@ -582,19 +561,9 @@ public:
   common::MapTemplate<Relational, DirectlyComparableTypes> u;
 };
 
-extern template struct Relational<Type<TypeCategory::Integer, 1>>;
-extern template struct Relational<Type<TypeCategory::Integer, 2>>;
-extern template struct Relational<Type<TypeCategory::Integer, 4>>;
-extern template struct Relational<Type<TypeCategory::Integer, 8>>;
-extern template struct Relational<Type<TypeCategory::Integer, 16>>;
-extern template struct Relational<Type<TypeCategory::Real, 2>>;
-extern template struct Relational<Type<TypeCategory::Real, 4>>;
-extern template struct Relational<Type<TypeCategory::Real, 8>>;
-extern template struct Relational<Type<TypeCategory::Real, 10>>;
-extern template struct Relational<Type<TypeCategory::Real, 16>>;
-extern template struct Relational<Type<TypeCategory::Character, 1>>;
-extern template struct Relational<Type<TypeCategory::Character, 2>>;
-extern template struct Relational<Type<TypeCategory::Character, 4>>;
+FOR_EACH_INTEGER_KIND(extern template struct Relational)
+FOR_EACH_REAL_KIND(extern template struct Relational)
+FOR_EACH_CHARACTER_KIND(extern template struct Relational)
 extern template struct Relational<SomeType>;
 
 template<int KIND>
@@ -611,17 +580,14 @@ private:
   using Operations =
       std::variant<Convert<Result, TypeCategory::Logical>, Parentheses<Result>,
           Not<KIND>, LogicalOperation<KIND>, Relational<SomeType>>;
-  using Others = std::variant<Constant<Result>, Designator<Result>,
-      FunctionReference<Result>>;
+  using Others =
+      std::variant<Constant<Result>, Designator<Result>, FunctionRef<Result>>;
 
 public:
   common::CombineVariants<Operations, Others> u;
 };
 
-extern template class Expr<Type<TypeCategory::Logical, 1>>;
-extern template class Expr<Type<TypeCategory::Logical, 2>>;
-extern template class Expr<Type<TypeCategory::Logical, 4>>;
-extern template class Expr<Type<TypeCategory::Logical, 8>>;
+FOR_EACH_LOGICAL_KIND(extern template class Expr)
 
 // A polymorphic expression of known intrinsic type category, but dynamic
 // kind, represented as a discriminated union over Expr<Type<CAT, K>>
@@ -649,7 +615,7 @@ public:
     : result{std::move(r)}, u{std::move(x)} {}
 
   Result result;
-  std::variant<Designator<Result>, FunctionReference<Result>> u;
+  std::variant<Designator<Result>, FunctionRef<Result>> u;
 };
 
 // A completely generic expression, polymorphic across all of the intrinsic type
@@ -700,41 +666,9 @@ struct GenericExprWrapper {
   Expr<SomeType> v;
 };
 
-extern template class Expr<SomeInteger>;
-extern template class Expr<SomeReal>;
-extern template class Expr<SomeComplex>;
-extern template class Expr<SomeCharacter>;
-extern template class Expr<SomeLogical>;
-extern template class Expr<SomeType>;
-
-extern template struct ExpressionBase<Type<TypeCategory::Integer, 1>>;
-extern template struct ExpressionBase<Type<TypeCategory::Integer, 2>>;
-extern template struct ExpressionBase<Type<TypeCategory::Integer, 4>>;
-extern template struct ExpressionBase<Type<TypeCategory::Integer, 8>>;
-extern template struct ExpressionBase<Type<TypeCategory::Integer, 16>>;
-extern template struct ExpressionBase<Type<TypeCategory::Real, 2>>;
-extern template struct ExpressionBase<Type<TypeCategory::Real, 4>>;
-extern template struct ExpressionBase<Type<TypeCategory::Real, 8>>;
-extern template struct ExpressionBase<Type<TypeCategory::Real, 10>>;
-extern template struct ExpressionBase<Type<TypeCategory::Real, 16>>;
-extern template struct ExpressionBase<Type<TypeCategory::Complex, 2>>;
-extern template struct ExpressionBase<Type<TypeCategory::Complex, 4>>;
-extern template struct ExpressionBase<Type<TypeCategory::Complex, 8>>;
-extern template struct ExpressionBase<Type<TypeCategory::Complex, 10>>;
-extern template struct ExpressionBase<Type<TypeCategory::Complex, 16>>;
-extern template struct ExpressionBase<Type<TypeCategory::Character, 1>>;
-extern template struct ExpressionBase<Type<TypeCategory::Character, 2>>;
-extern template struct ExpressionBase<Type<TypeCategory::Character, 4>>;
-extern template struct ExpressionBase<Type<TypeCategory::Logical, 1>>;
-extern template struct ExpressionBase<Type<TypeCategory::Logical, 2>>;
-extern template struct ExpressionBase<Type<TypeCategory::Logical, 4>>;
-extern template struct ExpressionBase<Type<TypeCategory::Logical, 8>>;
-extern template struct ExpressionBase<SomeInteger>;
-extern template struct ExpressionBase<SomeReal>;
-extern template struct ExpressionBase<SomeComplex>;
-extern template struct ExpressionBase<SomeCharacter>;
-extern template struct ExpressionBase<SomeLogical>;
-extern template struct ExpressionBase<SomeType>;
+FOR_EACH_CATEGORY_TYPE(extern template class Expr)
+FOR_EACH_INTRINSIC_KIND(extern template struct ExpressionBase)
+FOR_EACH_CATEGORY_TYPE(extern template struct ExpressionBase)
 
 }  // namespace Fortran::evaluate
 #endif  // FORTRAN_EVALUATE_EXPRESSION_H_
index 82045b248fe8259ccc04c7fa1553bfe03d8e02ab..c6b7dd9bbb5dea7c7edaf8ec19ceb15521be0d5c 100644 (file)
@@ -317,5 +317,53 @@ struct SomeType {
   using Scalar = GenericScalar;
 };
 
+// For "[extern] template class", &c. boilerplate
+#define FOR_EACH_INTEGER_KIND(PREFIX) \
+  PREFIX<Type<TypeCategory::Integer, 1>>; \
+  PREFIX<Type<TypeCategory::Integer, 2>>; \
+  PREFIX<Type<TypeCategory::Integer, 4>>; \
+  PREFIX<Type<TypeCategory::Integer, 8>>; \
+  PREFIX<Type<TypeCategory::Integer, 16>>;
+#define FOR_EACH_REAL_KIND(PREFIX) \
+  PREFIX<Type<TypeCategory::Real, 2>>; \
+  PREFIX<Type<TypeCategory::Real, 4>>; \
+  PREFIX<Type<TypeCategory::Real, 8>>; \
+  PREFIX<Type<TypeCategory::Real, 10>>; \
+  PREFIX<Type<TypeCategory::Real, 16>>;
+#define FOR_EACH_COMPLEX_KIND(PREFIX) \
+  PREFIX<Type<TypeCategory::Complex, 2>>; \
+  PREFIX<Type<TypeCategory::Complex, 4>>; \
+  PREFIX<Type<TypeCategory::Complex, 8>>; \
+  PREFIX<Type<TypeCategory::Complex, 10>>; \
+  PREFIX<Type<TypeCategory::Complex, 16>>;
+#define FOR_EACH_CHARACTER_KIND(PREFIX) \
+  PREFIX<Type<TypeCategory::Character, 1>>; \
+  PREFIX<Type<TypeCategory::Character, 2>>; \
+  PREFIX<Type<TypeCategory::Character, 4>>;
+#define FOR_EACH_LOGICAL_KIND(PREFIX) \
+  PREFIX<Type<TypeCategory::Logical, 1>>; \
+  PREFIX<Type<TypeCategory::Logical, 2>>; \
+  PREFIX<Type<TypeCategory::Logical, 4>>; \
+  PREFIX<Type<TypeCategory::Logical, 8>>;
+#define FOR_EACH_INTRINSIC_KIND(PREFIX) \
+  FOR_EACH_INTEGER_KIND(PREFIX) \
+  FOR_EACH_REAL_KIND(PREFIX) \
+  FOR_EACH_COMPLEX_KIND(PREFIX) \
+  FOR_EACH_CHARACTER_KIND(PREFIX) \
+  FOR_EACH_LOGICAL_KIND(PREFIX)
+#define FOR_EACH_SPECIFIC_TYPE(PREFIX) \
+  FOR_EACH_INTRINSIC_KIND(PREFIX) \
+  PREFIX<SomeDerived>;
+#define FOR_EACH_CATEGORY_TYPE(PREFIX) \
+  PREFIX<SomeInteger>; \
+  PREFIX<SomeReal>; \
+  PREFIX<SomeComplex>; \
+  PREFIX<SomeCharacter>; \
+  PREFIX<SomeLogical>; \
+  PREFIX<SomeType>;
+#define FOR_EACH_TYPE_AND_KIND(PREFIX) \
+  FOR_EACH_SPECIFIC_TYPE(PREFIX) \
+  FOR_EACH_CATEGORY_TYPE(PREFIX)
+
 }  // namespace Fortran::evaluate
 #endif  // FORTRAN_EVALUATE_TYPE_H_
index 2596a8b2a54b9b7e9c71f72594038e40845df267..fa3fc97fc1d9b7971b1a09d919f77a940284f255 100644 (file)
@@ -70,13 +70,14 @@ CoarrayRef::CoarrayRef(std::vector<const Symbol *> &&c,
   CHECK(!base_.empty());
 }
 
-CoarrayRef &CoarrayRef::setStat(Variable &&v) {
-  stat_ = CopyableIndirection<Variable>::Make(std::move(v));
+CoarrayRef &CoarrayRef::set_stat(Variable<DefaultInteger> &&v) {
+  stat_ = CopyableIndirection<Variable<DefaultInteger>>::Make(std::move(v));
   return *this;
 }
 
-CoarrayRef &CoarrayRef::setTeam(Variable &&v, bool isTeamNumber) {
-  team_ = CopyableIndirection<Variable>::Make(std::move(v));
+CoarrayRef &CoarrayRef::set_team(
+    Variable<DefaultInteger> &&v, bool isTeamNumber) {
+  team_ = CopyableIndirection<Variable<DefaultInteger>>::Make(std::move(v));
   teamIsTeamNumber_ = isTeamNumber;
   return *this;
 }
@@ -299,11 +300,10 @@ std::ostream &ProcedureDesignator::Dump(std::ostream &o) const {
   return Emit(o, u);
 }
 
-template<typename ARG>
-std::ostream &ProcedureRef<ARG>::Dump(std::ostream &o) const {
+std::ostream &UntypedFunctionRef::Dump(std::ostream &o) const {
   Emit(o, proc_);
   char separator{'('};
-  for (const auto &arg : argument_) {
+  for (const auto &arg : arguments_) {
     Emit(o << separator, arg);
     separator = ',';
   }
@@ -313,7 +313,18 @@ std::ostream &ProcedureRef<ARG>::Dump(std::ostream &o) const {
   return o << ')';
 }
 
-std::ostream &Variable::Dump(std::ostream &o) const { return Emit(o, u); }
+std::ostream &SubroutineCall::Dump(std::ostream &o) const {
+  Emit(o, proc_);
+  char separator{'('};
+  for (const auto &arg : arguments_) {
+    Emit(o << separator, arg);
+    separator = ',';
+  }
+  if (separator == '(') {
+    o << '(';
+  }
+  return o << ')';
+}
 
 std::ostream &ActualSubroutineArg::Dump(std::ostream &o) const {
   return Emit(o, u);
@@ -365,6 +376,11 @@ Expr<SubscriptInteger> ProcedureDesignator::LEN() const {
           }},
       u);
 }
+Expr<SubscriptInteger> UntypedFunctionRef::LEN() const {
+  // TODO: the results of the intrinsic functions REPEAT and TRIM have
+  // unpredictable lengths; maybe the concept of LEN() has to become dynamic
+  return proc_.LEN();
+}
 
 // Rank()
 int Component::Rank() const {
@@ -373,18 +389,6 @@ int Component::Rank() const {
   CHECK(baseRank == 0 || symbolRank == 0);
   return baseRank + symbolRank;
 }
-template<typename A> int ProcedureRef<A>::Rank() const {
-  if constexpr (std::is_same_v<A, ActualFunctionArg>) {  // FunctionRef
-    // TODO: Rank of elemental function reference depends on actual arguments
-    return std::visit(
-        common::visitors{[](IntrinsicProcedure) { return 0 /*TODO!!*/; },
-            [](const Symbol *sym) { return sym->Rank(); },
-            [](const Component &c) { return c.symbol().Rank(); }},
-        proc().u);
-  } else {
-    return 0;
-  }
-}
 int Subscript::Rank() const {
   return std::visit(common::visitors{[](const IndirectSubscriptIntegerExpr &x) {
                                        int rank{x->Rank()};
@@ -399,12 +403,13 @@ int ArrayRef::Rank() const {
   for (std::size_t j{0}; j < subscript.size(); ++j) {
     rank += subscript[j].Rank();
   }
-  int baseRank{std::visit(
-      common::visitors{[](const Symbol *symbol) { return symbol->Rank(); },
-          [](const auto &x) { return x.Rank(); }},
-      u)};
-  CHECK(rank == 0 || baseRank == 0);
-  return baseRank + rank;
+  if (std::holds_alternative<const Symbol *>(u)) {
+    return rank;
+  } else {
+    int baseRank{std::get_if<Component>(&u)->Rank()};
+    CHECK(rank == 0 || baseRank == 0);
+    return baseRank + rank;
+  }
 }
 int CoarrayRef::Rank() const {
   int rank{0};
@@ -425,16 +430,22 @@ int Substring::Rank() const {
       u_);
 }
 int ComplexPart::Rank() const { return complex_.Rank(); }
-int Variable::Rank() const {
-  return std::visit([](const auto &x) { return x.Rank(); }, u);
+int ProcedureDesignator::Rank() const {
+  return std::visit(
+      common::visitors{[](IntrinsicProcedure) { return 0 /*TODO!!*/; },
+          [](const Symbol *sym) { return sym->Rank(); },
+          [](const Component &c) { return c.symbol().Rank(); }},
+      u);
 }
 int ActualSubroutineArg::Rank() const {
-  return std::visit(
-      common::visitors{[](const CopyableIndirection<Expr<SomeType>> &x) {
-                         return x->Rank();
-                       },
-          [](const Label *) { return 0; },
-          [](const auto &x) { return x.Rank(); }},
+  return std::visit(common::visitors{[](const ActualFunctionArg &a) {
+                                       if (a.has_value()) {
+                                         return (*a)->Rank();
+                                       } else {
+                                         return 0;
+                                       }
+                                     },
+                        [](const Label *) { return 0; }},
       u);
 }
 
@@ -461,10 +472,14 @@ const Symbol *Substring::GetSymbol(bool first) const {
     return nullptr;  // substring of character literal
   }
 }
+const Symbol *ProcedureDesignator::GetSymbol() const {
+  return std::visit(common::visitors{[](const Symbol *sym) { return sym; },
+                        [](const Component &c) { return c.GetSymbol(false); },
+                        [](const auto &) -> const Symbol * { return nullptr; }},
+      u);
+}
+
+FOR_EACH_CHARACTER_KIND(template class Designator)
+FOR_EACH_SPECIFIC_TYPE(template class FunctionRef)
 
-template class Designator<Type<TypeCategory::Character, 1>>;
-template class Designator<Type<TypeCategory::Character, 2>>;
-template class Designator<Type<TypeCategory::Character, 4>>;
-template class ProcedureRef<ActualFunctionArg>;  // FunctionRef
-template class ProcedureRef<ActualSubroutineArg>;
 }  // namespace Fortran::evaluate
index 0125013c959dd64d9a4b68c731e59c812e4619c7..4954ef6d9b9fd19cdf9d66082b2e7569c031fc13 100644 (file)
@@ -39,7 +39,7 @@ using semantics::Symbol;
 // Forward declarations
 template<typename A> class Expr;
 struct DataRef;
-struct Variable;
+template<typename A> struct Variable;
 
 // Subscript and cosubscript expressions are of a kind that matches the
 // address size, at least at the top level.
@@ -133,8 +133,8 @@ public:
   CoarrayRef(std::vector<const Symbol *> &&,
       std::vector<Expr<SubscriptInteger>> &&,
       std::vector<Expr<SubscriptInteger>> &&);  // TODO: stat & team?
-  CoarrayRef &setStat(Variable &&);
-  CoarrayRef &setTeam(Variable &&, bool isTeamNumber = false);
+  CoarrayRef &set_stat(Variable<DefaultInteger> &&);
+  CoarrayRef &set_team(Variable<DefaultInteger> &&, bool isTeamNumber = false);
 
   int Rank() const;
   const Symbol *GetSymbol(bool first) const {
@@ -150,7 +150,7 @@ public:
 private:
   std::vector<const Symbol *> base_;
   std::vector<Expr<SubscriptInteger>> subscript_, cosubscript_;
-  std::optional<CopyableIndirection<Variable>> stat_, team_;
+  std::optional<CopyableIndirection<Variable<DefaultInteger>>> stat_, team_;
   bool teamIsTeamNumber_{false};  // false: TEAM=, true: TEAM_NUMBER=
 };
 
@@ -221,7 +221,8 @@ private:
 
 // R901 designator is the most general data reference object, apart from
 // calls to pointer-valued functions.  Its variant holds everything that
-// a DataRef can, and (when appropriate) a substring or complex part.
+// a DataRef can, and, when appropriate for the result type, a substring
+// reference or complex part (%RE/%IM).
 template<typename A> class Designator {
   using DataRefs = decltype(DataRef::u);
   using MaybeSubstring =
@@ -275,38 +276,67 @@ struct ProcedureDesignator {
   explicit ProcedureDesignator(IntrinsicProcedure p) : u{p} {}
   explicit ProcedureDesignator(const Symbol &n) : u{&n} {}
   Expr<SubscriptInteger> LEN() const;
+  int Rank() const;
+  const Symbol *GetSymbol() const;
   std::ostream &Dump(std::ostream &) const;
 
   std::variant<IntrinsicProcedure, const Symbol *, Component> u;
 };
 
-template<typename ARG> class ProcedureRef {
+using ActualFunctionArg = std::optional<CopyableIndirection<Expr<SomeType>>>;
+
+class UntypedFunctionRef {
 public:
-  using ArgumentType = CopyableIndirection<ARG>;
-  CLASS_BOILERPLATE(ProcedureRef)
-  ProcedureRef(ProcedureDesignator &&p, std::vector<ArgumentType> &&a)
-    : proc_{std::move(p)}, argument_(std::move(a)) {}
+  using Argument = ActualFunctionArg;
+  using Arguments = std::vector<Argument>;
+  CLASS_BOILERPLATE(UntypedFunctionRef)
+  UntypedFunctionRef(ProcedureDesignator &&p, Arguments &&a, int r)
+    : proc_{std::move(p)}, arguments_(std::move(a)), rank_{r} {}
+  UntypedFunctionRef(ProcedureDesignator &&p, Arguments &&a)
+    : proc_{std::move(p)}, arguments_(std::move(a)) {}
+
   const ProcedureDesignator &proc() const { return proc_; }
-  const std::vector<ArgumentType> &argument() const { return argument_; }
-  int Rank() const;
+  const Arguments &arguments() const { return arguments_; }
+
+  Expr<SubscriptInteger> LEN() const;
+  int Rank() const { return rank_; }
   std::ostream &Dump(std::ostream &) const;
 
-private:
+protected:
   ProcedureDesignator proc_;
-  std::vector<ArgumentType> argument_;
+  Arguments arguments_;
+  int rank_{proc_.Rank()};
 };
 
-// Subtlety: There is a distinction that must be maintained here between an
-// actual argument expression that *is* a variable and one that is not,
-// e.g. between X and (X).
-using ActualFunctionArg = CopyableIndirection<Expr<SomeType>>;
-using FunctionRef = ProcedureRef<ActualFunctionArg>;
+template<typename A> struct FunctionRef : public UntypedFunctionRef {
+  using Result = A;
+  static_assert(Result::isSpecificType);
+  // Subtlety: There is a distinction that must be maintained here between an
+  // actual argument expression that *is* a variable and one that is not,
+  // e.g. between X and (X).  The parser attempts to parse each argument
+  // first as a variable, then as an expression, and the distinction appears
+  // in the parse tree.
+  using Argument = ActualFunctionArg;
+  using Arguments = std::vector<Argument>;
+  CLASS_BOILERPLATE(FunctionRef)
+  explicit FunctionRef(UntypedFunctionRef &&ufr)
+    : UntypedFunctionRef{std::move(ufr)} {}
+  FunctionRef(ProcedureDesignator &&p, Arguments &&a, int r = 0)
+    : UntypedFunctionRef{std::move(p), std::move(a), r} {}
+};
 
-struct Variable {
+template<typename A> struct Variable {
+  using Result = A;
+  static_assert(Result::isSpecificType);
   EVALUATE_UNION_CLASS_BOILERPLATE(Variable)
-  int Rank() const;
-  std::ostream &Dump(std::ostream &) const;
-  std::variant<DataRef, Substring, ComplexPart, FunctionRef> u;
+  int Rank() const {
+    return std::visit([](const auto &x) { return x.Rank(); }, u);
+  }
+  std::ostream &Dump(std::ostream &o) const {
+    std::visit([&](const auto &x) { x.Dump(o); }, u);
+    return o;
+  }
+  std::variant<Designator<Result>, FunctionRef<Result>> u;
 };
 
 struct Label {  // TODO: this is a placeholder
@@ -319,22 +349,33 @@ struct Label {  // TODO: this is a placeholder
 class ActualSubroutineArg {
 public:
   EVALUATE_UNION_CLASS_BOILERPLATE(ActualSubroutineArg)
-  explicit ActualSubroutineArg(Expr<SomeType> &&x) : u{std::move(x)} {}
+  explicit ActualSubroutineArg(ActualFunctionArg &&x) : u{std::move(x)} {}
   explicit ActualSubroutineArg(const Label &l) : u{&l} {}
   int Rank() const;
   std::ostream &Dump(std::ostream &) const;
 
 public:
-  std::variant<CopyableIndirection<Expr<SomeType>>, Variable, const Label *> u;
+  std::variant<ActualFunctionArg, const Label *> u;
 };
 
-using SubroutineRef = ProcedureRef<ActualSubroutineArg>;
+class SubroutineCall {
+public:
+  using Argument = ActualSubroutineArg;
+  using Arguments = std::vector<Argument>;
+  CLASS_BOILERPLATE(SubroutineCall)
+  SubroutineCall(ProcedureDesignator &&p, Arguments &&a)
+    : proc_{std::move(p)}, arguments_(std::move(a)) {}
+  const ProcedureDesignator &proc() const { return proc_; }
+  const Arguments &arguments() const { return arguments_; }
+  int Rank() const { return 0; }  // TODO: elemental subroutine representation
+  std::ostream &Dump(std::ostream &) const;
+
+private:
+  ProcedureDesignator proc_;
+  Arguments arguments_;
+};
 
-extern template class Designator<Type<TypeCategory::Character, 1>>;
-extern template class Designator<Type<TypeCategory::Character, 2>>;
-extern template class Designator<Type<TypeCategory::Character, 4>>;
-extern template class ProcedureRef<ActualFunctionArg>;  // FunctionRef
-extern template class ProcedureRef<ActualSubroutineArg>;
+FOR_EACH_CHARACTER_KIND(extern template class Designator)
 
 }  // namespace Fortran::evaluate
 
index 291ea220066c77a07bb1aece131fd200a5b9b1f5..2bd1613c43abb8342c78f552b3183ed68994accc 100644 (file)
@@ -180,6 +180,9 @@ struct ExprAnalyzer {
   MaybeExpr TopLevelChecks(DataRef &&);
   void CheckUnsubscriptedComponent(const Component &);
 
+  std::optional<ProcedureDesignator> Procedure(
+      const parser::ProcedureDesignator &);
+
   FoldingContext context;
   const semantics::IntrinsicTypeDefaultKinds &defaults;
 };
@@ -480,12 +483,6 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
   return {AsGenericExpr(std::move(value.value))};
 }
 
-template<TypeCategory CATEGORY, typename DATAREF = DataRef>
-MaybeExpr DesignateHelper(int kind, DATAREF &&dataRef) {
-  return common::SearchDynamicTypes(
-      TypeKindVisitor<CATEGORY, Designator, DATAREF>{kind, std::move(dataRef)});
-}
-
 static std::optional<DynamicType> CategorizeSymbolType(const Symbol &symbol) {
   if (auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
     if (details->type().has_value()) {
@@ -504,40 +501,57 @@ static std::optional<DynamicType> CategorizeSymbolType(const Symbol &symbol) {
   return std::nullopt;
 }
 
+// Wraps a object in an explicitly typed representation (e.g., Designator<>
+// or FunctionRef<>) as instantiated on a dynamic type.
+// TODO: move to tools.h?
+template<TypeCategory CATEGORY, template<typename> typename WRAPPER,
+    typename WRAPPED>
+MaybeExpr WrapperHelper(int kind, WRAPPED &&x) {
+  return common::SearchDynamicTypes(
+      TypeKindVisitor<CATEGORY, WRAPPER, WRAPPED>{kind, std::move(x)});
+}
+
+template<template<typename> typename WRAPPER, typename WRAPPED>
+MaybeExpr TypedWrapper(DynamicType &&dyType, WRAPPED &&x) {
+  switch (dyType.category) {
+  case TypeCategory::Integer:
+    return WrapperHelper<TypeCategory::Integer, WRAPPER, WRAPPED>(
+        dyType.kind, std::move(x));
+  case TypeCategory::Real:
+    return WrapperHelper<TypeCategory::Real, WRAPPER, WRAPPED>(
+        dyType.kind, std::move(x));
+  case TypeCategory::Complex:
+    return WrapperHelper<TypeCategory::Complex, WRAPPER, WRAPPED>(
+        dyType.kind, std::move(x));
+  case TypeCategory::Character:
+    return WrapperHelper<TypeCategory::Character, WRAPPER, WRAPPED>(
+        dyType.kind, std::move(x));
+  case TypeCategory::Logical:
+    return WrapperHelper<TypeCategory::Logical, WRAPPER, WRAPPED>(
+        dyType.kind, std::move(x));
+  case TypeCategory::Derived:
+    return AsGenericExpr(
+        Expr<SomeDerived>{*dyType.derived, WRAPPER<SomeDerived>{std::move(x)}});
+  default: CRASH_NO_CASE;
+  }
+}
+
 // Wraps a data reference in a typed Designator<>.
 static MaybeExpr Designate(DataRef &&dataRef) {
   const Symbol &symbol{*dataRef.GetSymbol(false)};
-  if (std::optional<DynamicType> dynamicType{CategorizeSymbolType(symbol)}) {
-    switch (dynamicType->category) {
-    case TypeCategory::Integer:
-      return DesignateHelper<TypeCategory::Integer>(
-          dynamicType->kind, std::move(dataRef));
-    case TypeCategory::Real:
-      return DesignateHelper<TypeCategory::Real>(
-          dynamicType->kind, std::move(dataRef));
-    case TypeCategory::Complex:
-      return DesignateHelper<TypeCategory::Complex>(
-          dynamicType->kind, std::move(dataRef));
-    case TypeCategory::Character:
-      return DesignateHelper<TypeCategory::Character>(
-          dynamicType->kind, std::move(dataRef));
-    case TypeCategory::Logical:
-      return DesignateHelper<TypeCategory::Logical>(
-          dynamicType->kind, std::move(dataRef));
-    case TypeCategory::Derived:
-      return AsGenericExpr(Expr<SomeDerived>{
-          *dynamicType->derived, Designator<SomeDerived>{std::move(dataRef)}});
-    // TODO: graceful errors on CLASS(*) and TYPE(*) misusage
-    default: CRASH_NO_CASE;
-    }
+  if (std::optional<DynamicType> dyType{CategorizeSymbolType(symbol)}) {
+    return TypedWrapper<Designator, DataRef>(
+        std::move(*dyType), std::move(dataRef));
   }
+  // TODO: graceful errors on CLASS(*) and TYPE(*) misusage
   return std::nullopt;
 }
 
 MaybeExpr ExprAnalyzer::Analyze(const parser::Name &n) {
   if (n.symbol == nullptr) {
-    context.messages.Say(
-        n.source, "TODO INTERNAL: name was not resolved to a symbol"_err_en_US);
+    context.messages.Say(n.source,
+        "TODO INTERNAL: name '%s' was not resolved to a symbol"_err_en_US,
+        n.ToString().data());
   } else if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) {
     context.messages.Say(
         "TODO: PARAMETER references not yet implemented"_err_en_US);
@@ -579,8 +593,8 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Substring &ss) {
           if (std::optional<DynamicType> dynamicType{
                   CategorizeSymbolType(symbol)}) {
             if (dynamicType->category == TypeCategory::Character) {
-              return DesignateHelper<TypeCategory::Character, Substring>(
-                  dynamicType->kind,
+              return WrapperHelper<TypeCategory::Character, Designator,
+                  Substring>(dynamicType->kind,
                   Substring{
                       std::move(*checked), std::move(first), std::move(last)});
             }
@@ -820,11 +834,113 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::StructureConstructor &) {
   return std::nullopt;
 }
 
-MaybeExpr ExprAnalyzer::Analyze(const parser::FunctionReference &) {
+std::optional<ProcedureDesignator> ExprAnalyzer::Procedure(
+    const parser::ProcedureDesignator &pd) {
+  return std::visit(
+      common::visitors{
+          [&](const parser::Name &n) -> std::optional<ProcedureDesignator> {
+            if (n.symbol == nullptr) {
+              context.messages.Say(
+                  "TODO INTERNAL no symbol for procedure designator name '%s'"_err_en_US,
+                  n.ToString().data());
+              return std::nullopt;
+            }
+            return std::visit(
+                common::visitors{[&](const semantics::ProcEntityDetails &p)
+                                     -> std::optional<ProcedureDesignator> {
+                                   // TODO: capture &/or check interface vs.
+                                   // actual arguments
+                                   return {ProcedureDesignator{*n.symbol}};
+                                 },
+                    [&](const auto &) -> std::optional<ProcedureDesignator> {
+                      context.messages.Say(
+                          "TODO: unimplemented/invalid kind of symbol as procedure designator '%s'"_err_en_US,
+                          n.ToString().data());
+                      return std::nullopt;
+                    }},
+                n.symbol->details());
+          },
+          [&](const parser::ProcComponentRef &pcr)
+              -> std::optional<ProcedureDesignator> {
+            if (MaybeExpr component{AnalyzeHelper(*this, pcr.v)}) {
+              // TODO distinguish PCR from TBP
+              // TODO optional PASS argument for TBP
+              context.messages.Say("TODO: proc component ref"_err_en_US);
+              return std::nullopt;
+            } else {
+              return std::nullopt;
+            }
+          },
+      },
+      pd.u);
+}
+
+MaybeExpr ExprAnalyzer::Analyze(const parser::FunctionReference &funcRef) {
   // TODO: C1002: Allow a whole assumed-size array to appear if the dummy
   // argument would accept it.  Handle by special-casing the context
   // ActualArg -> Variable -> Designator.
-  context.messages.Say("TODO: FunctionReference unimplemented"_err_en_US);
+
+  std::optional<ProcedureDesignator> proc{
+      Procedure(std::get<parser::ProcedureDesignator>(funcRef.v.t))};
+
+  typename UntypedFunctionRef::Arguments arguments;
+  for (const auto &arg :
+      std::get<std::list<parser::ActualArgSpec>>(funcRef.v.t)) {
+    std::optional<parser::CharBlock> keyword;
+    if (const auto &argKW{std::get<std::optional<parser::Keyword>>(arg.t)}) {
+      keyword = argKW->v.source;
+    }
+    // TODO: look up dummy argument info by number/keyword
+    MaybeExpr actualArgExpr;
+    std::visit(
+        common::visitors{[&](const common::Indirection<parser::Variable> &v) {
+                           actualArgExpr = AnalyzeHelper(*this, v);
+                         },
+            [&](const common::Indirection<parser::Expr> &x) {
+              actualArgExpr = Analyze(*x);
+            },
+            [&](const parser::Name &n) {
+              context.messages.Say("TODO: procedure name actual arg"_err_en_US);
+            },
+            [&](const parser::ProcComponentRef &) {
+              context.messages.Say(
+                  "TODO: proc component ref actual arg"_err_en_US);
+            },
+            [&](const parser::AltReturnSpec &) {
+              context.messages.Say(
+                  "alternate return specification cannot appear on function reference"_err_en_US);
+            },
+            [&](const parser::ActualArg::PercentRef &) {
+              context.messages.Say("TODO: %REF() argument"_err_en_US);
+            },
+            [&](const parser::ActualArg::PercentVal &) {
+              context.messages.Say("TODO: %VAL() argument"_err_en_US);
+            }},
+        std::get<parser::ActualArg>(arg.t).u);
+    if (actualArgExpr.has_value()) {
+      CopyableIndirection<Expr<SomeType>> indExpr{std::move(*actualArgExpr)};
+      arguments.emplace_back(std::move(indExpr));
+    } else {
+      arguments.emplace_back();
+    }
+  }
+  // TODO: validate arguments against interface
+  // TODO: distinguish applications of elemental functions
+  // TODO: map generic to specific procedure
+
+  if (proc.has_value()) {
+    std::optional<DynamicType> dyType;
+    if (const Symbol * symbol{proc->GetSymbol()}) {
+      dyType = CategorizeSymbolType(*symbol);
+    } else {
+      // TODO: intrinsic function result type - this is a placeholder
+      dyType = DynamicType{TypeCategory::Real, 4};
+    }
+    if (dyType.has_value()) {
+      return TypedWrapper<FunctionRef, UntypedFunctionRef>(std::move(*dyType),
+          UntypedFunctionRef{std::move(*proc), std::move(arguments)});
+    }
+  }
   return std::nullopt;
 }
 
@@ -1120,7 +1236,7 @@ public:
         expr.typedExpr.reset(
             new evaluate::GenericExprWrapper{std::move(*checked)});
       } else {
-        std::cout << "expression analysis failed for this expression: ";
+        std::cout << "TODO: expression analysis failed for this expression: ";
         DumpTree(std::cout, expr);
       }
     }