[flang] Checkpoint: derived type component iterators
authorJean Perier <jperier@nvidia.com>
Wed, 31 Jul 2019 14:19:22 +0000 (07:19 -0700)
committerJean Perier <jperier@nvidia.com>
Wed, 31 Jul 2019 14:26:26 +0000 (07:26 -0700)
Original-commit: flang-compiler/f18@72d209bb52d28aedc8335c8175a5ffb5bce161fc
Reviewed-on: https://github.com/flang-compiler/f18/pull/607
Tree-same-pre-rewrite: false

flang/lib/semantics/check-allocate.cc
flang/lib/semantics/expression.cc
flang/lib/semantics/symbol.cc
flang/lib/semantics/symbol.h
flang/lib/semantics/tools.cc
flang/lib/semantics/tools.h

index b3b2444..6a509b5 100644 (file)
@@ -119,14 +119,13 @@ static std::optional<AllocateCheckerInfo> CheckAllocateOptions(
     info.typeSpecLoc = parser::FindSourceLocation(*typeSpec);
     if (const DerivedTypeSpec * derived{info.typeSpec->AsDerived()}) {
       // C937
-      if (auto coarraySearch{ComponentVisitor::HasCoarrayUltimate(*derived)}) {
+      if (auto it{FindCoarrayUltimateComponent(*derived)}) {
         context
             .Say("Type-spec in ALLOCATE must not specify a type with a coarray"
                  " ultimate component"_err_en_US)
-            .Attach(coarraySearch.Result()->name(),
+            .Attach((*it)->name(),
                 "Type '%s' has coarray ultimate component '%s' declared here"_en_US,
-                info.typeSpec->AsFortran(),
-                coarraySearch.BuildResultDesignatorName());
+                info.typeSpec->AsFortran(), it.BuildResultDesignatorName());
       }
     }
   }
@@ -207,31 +206,30 @@ static std::optional<AllocateCheckerInfo> CheckAllocateOptions(
         const DerivedTypeSpec &derived{
             info.sourceExprType.value().GetDerivedTypeSpec()};
         // C949
-        if (auto coarraySearch{ComponentVisitor::HasCoarrayUltimate(derived)}) {
+        if (auto it{FindCoarrayUltimateComponent(derived)}) {
           context
               .Say(parserSourceExpr->source,
                   "SOURCE or MOLD expression must not have a type with a coarray ultimate component"_err_en_US)
-              .Attach(coarraySearch.Result()->name(),
+              .Attach((*it)->name(),
                   "Type '%s' has coarray ultimate component '%s' declared here"_en_US,
                   info.sourceExprType.value().AsFortran(),
-                  coarraySearch.BuildResultDesignatorName());
+                  it.BuildResultDesignatorName());
         }
         if (info.gotSrc) {
           // C948
           if (IsEventTypeOrLockType(&derived)) {
             context.Say(parserSourceExpr->source,
                 "SOURCE expression type must not be EVENT_TYPE or LOCK_TYPE from ISO_FORTRAN_ENV"_err_en_US);
-          } else if (auto componentSearch{
-                         ComponentVisitor::HasEventOrLockPotential(derived)}) {
+          } else if (auto it{FindEventOrLockPotentialComponent(derived)}) {
             context
                 .Say(parserSourceExpr->source,
                     "SOURCE expression type must not have potential subobject "
                     "component"
                     " of type EVENT_TYPE or LOCK_TYPE from ISO_FORTRAN_ENV"_err_en_US)
-                .Attach(componentSearch.Result()->name(),
+                .Attach((*it)->name(),
                     "Type '%s' has potential ultimate component '%s' declared here"_en_US,
                     info.sourceExprType.value().AsFortran(),
-                    componentSearch.BuildResultDesignatorName());
+                    it.BuildResultDesignatorName());
           }
         }
       }
index fe24818..37f1a06 100644 (file)
@@ -1199,8 +1199,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
   // produces the component list X, A, Y.
   // The order is important below because a structure constructor can
   // initialize X or A by name, but not both.
-  const auto &details{typeSymbol.get<semantics::DerivedTypeDetails>()};
-  semantics::SymbolVector components{details.OrderComponents(*spec.scope())};
+  auto components{semantics::OrderedComponentIterator{spec}};
   auto nextAnonymous{components.begin()};
 
   std::set<parser::CharBlock> unavailable;
index 51de133..1e718cf 100644 (file)
@@ -564,25 +564,6 @@ void DerivedTypeDetails::add_component(const Symbol &symbol) {
   componentNames_.push_back(symbol.name());
 }
 
-SymbolVector DerivedTypeDetails::OrderComponents(const Scope &scope) const {
-  SymbolVector result;
-  for (SourceName name : componentNames_) {
-    auto iter{scope.find(name)};
-    if (iter != scope.cend()) {
-      const Symbol &symbol{*iter->second};
-      if (symbol.test(Symbol::Flag::ParentComp)) {
-        CHECK(result.empty());  // parent component must appear first
-        const DerivedTypeSpec &spec{
-            symbol.get<ObjectEntityDetails>().type()->derivedTypeSpec()};
-        result = spec.typeSymbol().get<DerivedTypeDetails>().OrderComponents(
-            *spec.scope());
-      }
-      result.push_back(&symbol);
-    }
-  }
-  return result;
-}
-
 const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
   if (auto extends{GetParentComponentName()}) {
     if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
index bde940c..c9e30a6 100644 (file)
@@ -223,12 +223,9 @@ public:
   void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(&symbol); }
   void add_component(const Symbol &);
   void set_sequence(bool x = true) { sequence_ = x; }
-
-  // Returns the complete list of derived type components in the order
-  // in which their declarations appear in the derived type definitions
-  // (parents first).  Parent components appear in the list immediately
-  // after the components that belong to them.
-  SymbolVector OrderComponents(const Scope &) const;
+  const std::list<SourceName> &componentNames() const {
+    return componentNames_;
+  }
 
   // If this derived type extends another, locate the parent component's symbol.
   const Symbol *GetParentComponent(const Scope &) const;
index f0abd93..b0fdee8 100644 (file)
@@ -386,21 +386,13 @@ const bool IsEventTypeOrLockType(const DerivedTypeSpec *derivedTypeSpec) {
       IsDerivedTypeFromModule(derivedTypeSpec, "iso_fortran_env", "lock_type");
 }
 
-static const bool IsEventTypeOrLockTypeObjectEntity(const Symbol &symbol) {
-  if (symbol.has<ObjectEntityDetails>()) {
-    const DeclTypeSpec *type{symbol.GetType()};
-    return type && IsEventTypeOrLockType(type->AsDerived());
-  }
-  return false;
-}
-
 bool IsOrContainsEventOrLockComponent(const Symbol &symbol) {
   if (const Symbol * root{GetAssociationRoot(symbol)}) {
     if (const auto *details{root->detailsIf<ObjectEntityDetails>()}) {
       if (const DeclTypeSpec * type{details->type()}) {
         if (const DerivedTypeSpec * derived{type->AsDerived()}) {
           return IsEventTypeOrLockType(derived) ||
-              ComponentVisitor::HasEventOrLockPotential(*derived);
+              FindEventOrLockPotentialComponent(*derived);
         }
       }
     }
@@ -738,152 +730,218 @@ static Symbol &InstantiateSymbol(
   return result;
 }
 
-enum class ComponentKind { Direct, Ultimate, Potential };
-
-template<ComponentKind componentKind> class ComponentVisitorImplementation {
-public:
-  ComponentVisitorImplementation(std::function<bool(const Symbol &)> &predicate)
-    : predicate_{predicate} {}
-  SymbolVector Visit(const DerivedTypeSpec &derived) {
-    TraverseDerivedType(derived);
-    return std::move(componentStack_);
-  }
-
-private:
-  const Symbol *TraverseDerivedType(const DerivedTypeSpec &derived) {
-    const Symbol &derivedTypeSymbol{derived.typeSymbol()};
-    // Avoid infinite loop if the type is already part of the types
-    // being visited. It is possible to have "loops in type" because
-    // C744 does not forbid to use not yet declared type for
-    // ALLOCATABLE or POINTER components.
-    // When looking for potential components, the search could fall
-    // in an infinite loop. Avoid these in other search for safety.
-    for (const Symbol *typeUnderVisit : typeStack_) {
-      if (typeUnderVisit == &derivedTypeSymbol) {
-        return nullptr;
-      }
-    }
-    typeStack_.push_back(&derivedTypeSymbol);
-    const Scope *scope{derivedTypeSymbol.scope()};
-    CHECK(scope);  // derived type symbol must have a scope
-    const Symbol *result{nullptr};
-    // Note: parent subcomponents are visited first, then the parent component
-    // (if any), then other components by order of declaration
-    SymbolVector orederedComponents{
-        derivedTypeSymbol.get<DerivedTypeDetails>().OrderComponents(*scope)};
-    for (const Symbol *component : orederedComponents) {
-      if (component->has<ProcEntityDetails>()) {
-        result = VisitProcedureComponent(*component);
-      } else if (component->has<ObjectEntityDetails>()) {
-        result = VisitDataComponent(*component);
-      }
-      if (result) {
-        return result;
-      }
-    }
-    typeStack_.pop_back();
-    return nullptr;
+// ComponentIterator implementation
+
+template<ComponentKind componentKind>
+typename ComponentIterator<componentKind>::const_iterator
+ComponentIterator<componentKind>::const_iterator::Create(
+    const DerivedTypeSpec &derived) {
+  const_iterator it{};
+  const std::list<SourceName> &names{
+      derived.typeSymbol().get<DerivedTypeDetails>().componentNames()};
+  if (names.empty()) {
+    return it;  // end iterator
+  } else {
+    it.componentPath_.emplace_back(
+        ComponentPathNode{nullptr, &derived, names.cbegin()});
+    it.Increment();  // search first relevant component (may be the end)
+    return it;
   }
+}
 
-  const Symbol *VisitProcedureComponent(const Symbol &component) {
-    // Procedure components are pointers (C756)
-    if constexpr (componentKind == ComponentKind::Ultimate ||
-        componentKind == ComponentKind::Direct) {
-      if (predicate_(component)) {
-        componentStack_.push_back(&component);
-        return &component;
+template<ComponentKind componentKind>
+bool ComponentIterator<componentKind>::const_iterator::PlanComponentTraversal(
+    const Symbol &component) {
+  // only data component can be traversed
+  if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) {
+    const DeclTypeSpec *type{details->type()};
+    if (!type) {
+      return false;  // error recovery
+    } else if (const auto *derived{type->AsDerived()}) {
+      bool traverse{false};
+      if constexpr (componentKind == ComponentKind::Ordered) {
+        // Order Component (only visit parents)
+        traverse = component.test(Symbol::Flag::ParentComp);
+      } else if constexpr (componentKind == ComponentKind::Direct) {
+        traverse = !IsAllocatableOrPointer(component);
+      } else if constexpr (componentKind == ComponentKind::Ultimate) {
+        traverse = !IsAllocatableOrPointer(component);
+      } else if constexpr (componentKind == ComponentKind::Potential) {
+        traverse = !IsPointer(component);
       }
-    }
-    return nullptr;
+      if (traverse) {
+        const Symbol *newTypeSymbol{&derived->typeSymbol()};
+        // Avoid infinite loop if the type is already part of the types
+        // being visited. It is possible to have "loops in type" because
+        // C744 does not forbid to use not yet declared type for
+        // ALLOCATABLE or POINTER components.
+        for (const auto &node : componentPath_) {
+          if (newTypeSymbol == &GetTypeSymbol(node)) {
+            return false;
+          }
+        }
+        componentPath_.emplace_back(ComponentPathNode{nullptr, derived,
+            newTypeSymbol->get<DerivedTypeDetails>()
+                .componentNames()
+                .cbegin()});
+        return true;
+      }
+    }  // intrinsic & unlimited polymorphic not traversable
   }
+  return false;
+}
 
-  const Symbol *VisitDataComponent(const Symbol &component) {
-    const DeclTypeSpec *type{component.GetType()};
-    if (!type) {
-      return nullptr;  // error recovery ?
-    }
-    bool test{false}, descend{false};
-    if constexpr (componentKind == ComponentKind::Direct) {
-      test = true;
-      descend = !IsAllocatableOrPointer(component);
-    } else if constexpr (componentKind == ComponentKind::Ultimate) {
-      descend = !IsAllocatableOrPointer(component);
-      test = !descend || type->AsIntrinsic();
-    } else {  // Potential
-      test = descend = !IsPointer(component);
-    }
+template<ComponentKind componentKind>
+static bool StopAtComponentPre(const Symbol &component) {
+  if constexpr (componentKind == ComponentKind::Ordered) {
+    // Parent components need to be iterated upon after their
+    // sub-components in structure constructor analysis.
+    return !component.test(Symbol::Flag::ParentComp);
+  } else if constexpr (componentKind == ComponentKind::Direct) {
+    return true;
+  } else if constexpr (componentKind == ComponentKind::Ultimate) {
+    return component.has<ProcEntityDetails>() ||
+        IsAllocatableOrPointer(component) ||
+        (component.get<ObjectEntityDetails>().type() &&
+            component.get<ObjectEntityDetails>().type()->AsIntrinsic());
+  } else if constexpr (componentKind == ComponentKind::Potential) {
+    return !IsPointer(component);
+  }
+}
+
+template<ComponentKind componentKind>
+static bool StopAtComponentPost(const Symbol &component) {
+  if constexpr (componentKind == ComponentKind::Ordered) {
+    return component.test(Symbol::Flag::ParentComp);
+  } else {
+    return false;
+  }
+}
 
-    // Do not descend into parent components, their components were already
-    // included by DerivedTypeDetails::OrderComponents. However, parent
-    // components should still be checked against the predicate if relevant.
-    descend &= !component.test(Symbol::Flag::ParentComp);
-
-    if (test && predicate_(component)) {
-      componentStack_.push_back(&component);
-      return &component;
-    } else if (descend) {
-      if (const auto *derived{type->AsDerived()}) {
-        componentStack_.push_back(&component);
-        if (const Symbol * result{TraverseDerivedType(*derived)}) {
-          return result;
+enum class ComponentVisitState { Resume, Pre, Post };
+
+template<ComponentKind componentKind>
+void ComponentIterator<componentKind>::const_iterator::Increment() {
+  std::int64_t level{static_cast<std::int64_t>(componentPath_.size()) - 1};
+  // Need to know if this is the first incrementation or if the visit is resumed
+  // after a user increment.
+  ComponentVisitState state{
+      level >= 0 && GetComponentSymbol(componentPath_[level])
+          ? ComponentVisitState::Resume
+          : ComponentVisitState::Pre};
+  while (level >= 0) {
+    bool descend{false};
+    const Scope *scope{GetScope(componentPath_[level])};
+    CHECK(scope);
+    auto &levelIterator{GetIterator(componentPath_[level])};
+    const auto &levelEndIterator{GetTypeSymbol(componentPath_[level])
+                                     .template get<DerivedTypeDetails>()
+                                     .componentNames()
+                                     .cend()};
+
+    while (!descend && levelIterator != levelEndIterator) {
+      const Symbol *component{GetComponentSymbol(componentPath_[level])};
+
+      switch (state) {
+      case ComponentVisitState::Resume:
+        CHECK(component);
+        if (StopAtComponentPre<componentKind>(*component)) {
+          // The symbol was not yet considered for
+          // traversal.
+          descend = PlanComponentTraversal(*component);
         }
-        componentStack_.pop_back();
+        break;
+      case ComponentVisitState::Pre:
+        // Search iterator
+        if (auto iter{scope->find(*levelIterator)}; iter != scope->cend()) {
+          const Symbol *newComponent{iter->second};
+          SetComponentSymbol(componentPath_[level], newComponent);
+          if (StopAtComponentPre<componentKind>(*newComponent)) {
+            return;
+          }
+          descend = PlanComponentTraversal(*newComponent);
+          if (!descend && StopAtComponentPost<componentKind>(*newComponent)) {
+            return;
+          }
+        }
+        break;
+      case ComponentVisitState::Post:
+        CHECK(component);
+        if (StopAtComponentPost<componentKind>(*component)) {
+          return;
+        }
+        break;
       }
-    }
-    return nullptr;
-  }
 
-  std::vector<const Symbol *> componentStack_;  // to build message info
-  std::vector<const Symbol *> typeStack_;  // to avoid infinite loops
-  std::function<bool(const Symbol &)> &predicate_;
-};
+      if (descend) {
+        level++;
+      } else {
+        SetComponentSymbol(componentPath_[level], nullptr);  // safety
+        levelIterator++;
+      }
+      state = ComponentVisitState::Pre;
+    }
 
-ComponentVisitor &ComponentVisitor::VisitPotentialComponents(
-    const DerivedTypeSpec &derived) {
-  componentStack_.clear();
-  componentStack_ =
-      ComponentVisitorImplementation<ComponentKind::Potential>{predicate_}
-          .Visit(derived);
-  return *this;
+    if (!descend) {  // Finished level traversal
+      componentPath_.pop_back();
+      --level;
+      state = ComponentVisitState::Post;
+    }
+  }
+  // iterator reached end of components
 }
 
-ComponentVisitor &ComponentVisitor::VisitUltimateComponents(
-    const DerivedTypeSpec &derived) {
-  componentStack_.clear();
-  componentStack_ =
-      ComponentVisitorImplementation<ComponentKind::Ultimate>{predicate_}.Visit(
-          derived);
-  return *this;
+template<ComponentKind componentKind>
+std::string
+ComponentIterator<componentKind>::const_iterator::BuildResultDesignatorName()
+    const {
+  std::string designator{""};
+  for (const auto &node : componentPath_) {
+    designator += "%" + GetComponentSymbol(node)->name().ToString();
+  }
+  return designator;
 }
 
-ComponentVisitor &ComponentVisitor::VisitDirectComponents(
-    const DerivedTypeSpec &derived) {
-  componentStack_.clear();
-  componentStack_ =
-      ComponentVisitorImplementation<ComponentKind::Direct>{predicate_}.Visit(
-          derived);
-  return *this;
-}
+template class ComponentIterator<ComponentKind::Ordered>;
+template class ComponentIterator<ComponentKind::Direct>;
+template class ComponentIterator<ComponentKind::Ultimate>;
+template class ComponentIterator<ComponentKind::Potential>;
 
-ComponentVisitor ComponentVisitor::HasEventOrLockPotential(
+UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
     const DerivedTypeSpec &derived) {
-  return ComponentVisitor{IsEventTypeOrLockTypeObjectEntity}
-      .VisitPotentialComponents(derived);
+  UltimateComponentIterator ultimates{derived};
+  return std::find_if(
+      ultimates.begin(), ultimates.end(), [](const Symbol *component) {
+        CHECK(component);
+        return component->Corank() > 0;
+      });
 }
 
-std::string ComponentVisitor::BuildResultDesignatorName() const {
-  std::string designator{""};
-  for (const Symbol *component : componentStack_) {
-    designator += "%" + component->name().ToString();
-  }
-  return designator;
+PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent(
+    const DerivedTypeSpec &derived) {
+  PotentialComponentIterator potentials{derived};
+  return std::find_if(
+      potentials.begin(), potentials.end(), [](const Symbol *component) {
+        CHECK(component);
+        if (const auto *details{component->detailsIf<ObjectEntityDetails>()}) {
+          const DeclTypeSpec *type{details->type()};
+          return type && IsEventTypeOrLockType(type->AsDerived());
+        }
+        return false;
+      });
 }
 
 const Symbol *FindUltimateComponent(const DerivedTypeSpec &derived,
     std::function<bool(const Symbol &)> predicate) {
-  return ComponentVisitor{std::move(predicate)}
-      .VisitUltimateComponents(derived)
-      .Result();
+  UltimateComponentIterator ultimates{derived};
+  if (auto it{std::find_if(ultimates.begin(), ultimates.end(),
+          [&predicate](const Symbol *component) -> bool {
+            CHECK(component);
+            return predicate(*component);
+          })}) {
+    return *it;
+  }
+  return nullptr;
 }
 
 }
index 51fed7a..9ca98c9 100644 (file)
@@ -207,55 +207,160 @@ template<typename T> std::optional<std::int64_t> GetIntValue(const T &x) {
   }
 }
 
-// Derived type component visitor that applies a predicate on all the direct,
-// ultimate or Potential components. It stops at the first component that
-// verifies the given predicate and keep the component path to the result
-// (included at the end of the path). If no component verifies the predicate
-// the path is empty.
-// The component tree is visited in component declaration order,
-// visiting the subcomponent of a component before visiting the next component.
-// Parent components and procedure pointer components are visited.
-// Note that it is made in such a way that one can easily test and build info
-// message in the following way:
-//    if (auto
-//      visitor{ComponentVisitor{predicate}.VisitDirectComponents(derived)}) {
-//       msg = visitor.BuildResultDesignatorName() + " verifies predicates";
+// Derived type component iterator that provides a C++ LegacyForwadIterator
+// iterator over the Ordered, Direct, Ultimate or Potential components of a
+// DerivedTypeSpec. These iterators can be used with STL algorithms
+// accepting LegacyForwadIterator.
+// The kind of component is a template argument of the iterator factory
+// ComponentIterator.
+//
+//
+// - Ordered components are the components from the component order defined
+// in 7.5.4.7, except that the parent components IS added between the parent
+// component order and the components in order of declaration.
+// This "deviation" is important for structure-constructor analysis.
+// For this kind of iterator, the component tree is recursively visited in the
+// following order:
+//  - first, the Ordered components of the parent type (if relevant)
+//  - then, the parent component (if relevant, different from 7.5.4.7!)
+//  - then, the components in declaration order (without visiting subcomponents)
+//
+// - Ultimate, Direct and Potential components are as defined in 7.5.1.
+// Parent and procedure components are considered against these definitions.
+// For this kind of iterator, the component tree is recursively visited in the
+// following order:
+//  - the parent component first (if relevant)
+//  - then, the components of the parent type (if relevant)
+//      + visiting the component and then, if it is derived type data component,
+//        visiting the subcomponents before visiting the next
+//        component in declaration order.
+//  - then, components in declaration order, similarly to components of parent
+//    type.
+//  Here, the parent component is visited first so that search for a component
+//  verifying a property will never descend into a component that already
+//  verifies the property (this helps giving clearer feedback).
+//
+// ComponentIterator::const_iterator remain valid during the whole lifetime of
+// the DerivedTypeSpec passed by reference to the ComponentIterator factory.
+// Their validity is independent of the ComponentIterator factory lifetime.
+//
+// For safety and simplicity, the iterators are read only and can only be
+// incremented. This could be changed if desired.
+//
+// Note that iterators are made in such a way that one can easily test and build
+// info message in the following way:
+//    ComponentIterator<ComponentIterator> comp{derived}
+//    if (auto it{std::find_if(comp.begin(), comp.end(), predicate)}) {
+//       msg = it.BuildResultDesignatorName() + " verifies predicates";
+//       const Symbol* component{*it};
 //       ....
 //    }
-// It is safe to re-use the same object several times, previous results are
-// cleared before each visit.
-class ComponentVisitor {
+
+ENUM_CLASS(ComponentKind, Ordered, Direct, Ultimate, Potential)
+
+template<ComponentKind componentKind> class ComponentIterator {
 public:
-  ComponentVisitor(std::function<bool(const Symbol &)> &&predicate)
-    : predicate_{std::move(predicate)} {}
-
-  // Object is updated with the result during visit and returned by ref
-  ComponentVisitor &VisitPotentialComponents(const DerivedTypeSpec &);
-  ComponentVisitor &VisitUltimateComponents(const DerivedTypeSpec &);
-  ComponentVisitor &VisitDirectComponents(const DerivedTypeSpec &);
-
-  // Predefined common tests
-  // Look for an ultimate component that is a coarray.
-  static ComponentVisitor HasCoarrayUltimate(const DerivedTypeSpec &derived) {
-    return ComponentVisitor{IsCoarray}.VisitUltimateComponents(derived);
-  }
-  // Look for a potential component of EVENT_TYPE or LOCK_TYPE from
-  // ISO_FORTRAN_ENV module.
-  static ComponentVisitor HasEventOrLockPotential(const DerivedTypeSpec &);
+  ComponentIterator(const DerivedTypeSpec &derived) : derived_{derived} {}
+  class const_iterator {
+  public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = const Symbol *;
+    using difference_type = void;
+    using pointer = const value_type *;
+    using reference = const value_type &;
 
-  const Symbol *Result() const {
-    return componentStack_.empty() ? nullptr : componentStack_.back();
-  }
+    static const_iterator Create(const DerivedTypeSpec &);
+
+    const_iterator &operator++() {
+      Increment();
+      return *this;
+    }
+    const_iterator operator++(int) {
+      const_iterator tmp(*this);
+      Increment();
+      return tmp;
+    }
+    reference operator*() const {
+      CHECK(!componentPath_.empty());
+      return std::get<0>(componentPath_.back());
+    }
 
-  bool HasResult() const { return Result() != nullptr; }
-  explicit operator bool() const { return HasResult(); }
-  // build designator name for messages if there is a result
-  std::string BuildResultDesignatorName() const;
+    bool operator==(const const_iterator &other) const {
+      return componentPath_ == other.componentPath_;
+    }
+    bool operator!=(const const_iterator &other) const {
+      return !(*this == other);
+    }
+
+    // bool() operator indicates if the iterator can be dereferenced without
+    // having to check against an end() iterator.
+    explicit operator bool() const {
+      return !componentPath_.empty() &&
+          GetComponentSymbol(componentPath_.back());
+    }
+
+    // Build a designator name of the referenced component for messages.
+    // The designator helps when the component referred to by the iterator
+    // may be "buried" into other components. This gives the full
+    // path inside the iterated derived type: e.g "%a%b%c%ultimate"
+    // when (*it)->names() only gives "ultimate". Parent component are
+    // part of the path for clarity, even though they could be
+    // skipped.
+    std::string BuildResultDesignatorName() const;
+
+  private:
+    using name_iterator = typename std::list<SourceName>::const_iterator;
+    using ComponentPathNode =
+        std::tuple<const Symbol *, const DerivedTypeSpec *, name_iterator>;
+    using ComponentPath = std::vector<ComponentPathNode>;
+
+    static const Symbol *GetComponentSymbol(const ComponentPathNode &node) {
+      return std::get<0>(node);
+    }
+    static void SetComponentSymbol(ComponentPathNode &node, const Symbol *sym) {
+      std::get<0>(node) = sym;
+    }
+    static const Symbol &GetTypeSymbol(const ComponentPathNode &node) {
+      return std::get<1>(node)->typeSymbol();
+    }
+    static const Scope *GetScope(const ComponentPathNode &node) {
+      return std::get<1>(node)->scope();
+    }
+    static name_iterator &GetIterator(ComponentPathNode &node) {
+      return std::get<2>(node);
+    }
+    bool PlanComponentTraversal(const Symbol &component);
+    void Increment();
+    ComponentPath componentPath_;
+  };
+
+  const_iterator begin() { return cbegin(); }
+  const_iterator end() { return cend(); }
+  const_iterator cbegin() { return const_iterator::Create(derived_); }
+  const_iterator cend() { return const_iterator{}; }
 
 private:
-  SymbolVector componentStack_;  // component path to result
-  std::function<bool(const Symbol &)> predicate_;
+  const DerivedTypeSpec &derived_;
 };
 
+extern template class ComponentIterator<ComponentKind::Ordered>;
+extern template class ComponentIterator<ComponentKind::Direct>;
+extern template class ComponentIterator<ComponentKind::Ultimate>;
+extern template class ComponentIterator<ComponentKind::Potential>;
+using OrderedComponentIterator = ComponentIterator<ComponentKind::Ordered>;
+using DirectComponentIterator = ComponentIterator<ComponentKind::Direct>;
+using UltimateComponentIterator = ComponentIterator<ComponentKind::Ultimate>;
+using PotentialComponentIterator = ComponentIterator<ComponentKind::Potential>;
+
+// Common component searches, the iterator returned is referring to the first
+// component, according to the order defined for the related ComponentIterator,
+// that verifies the property from the name.
+// If no components verifies the property, an end iterator (casting to false)
+// is returned. Otherwise, the returned iterator cast to true and can be
+// dereferenced.
+PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent(
+    const DerivedTypeSpec &);
+UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
+    const DerivedTypeSpec &);
 }
 #endif  // FORTRAN_SEMANTICS_TOOLS_H_