Repository: carbon-language/carbon-lang
File: toolchain/sem_ir/type_iterator.h (C/C++)

Code before:
    SemIR::NameId name_id;
  };

  // A *Start type, but without anything following it, so we also skip the
  // matching `End`.
  struct StartOnly {
    using Any =
        std::variant<ClassStart, StructStart, TupleStart, InterfaceStart>;
    Any any;
  };
  // A *Start type, with nested steps after it, and then a matching `End`.
  struct StartWithEnd {
    using Any =
        std::variant<ClassStart, StructStart, TupleStart, InterfaceStart,
                     ArrayStart, IntStart, PointerStart>;
    Any any;
  };

  // Closes the scope of a `StartWithEnd`.
  struct End {};

  // Iteration is complete.
  struct Done {};

  // Each step is one of these.
  using Any = std::variant<ConcreteType, SymbolicType, TemplateType,
                           ConcreteValue, SymbolicValue, StructFieldName,
                           StartOnly, StartWithEnd, End, Done>;

  template <class T>
  auto Is() const -> bool {
    return std::holds_alternative<T>(any);
  }

  // Converts from any individual step.
  template <class T>
    requires std::constructible_from<Any, T>
  // NOLINTNEXTLINE(google-explicit-constructor)
  Step(T any) : any(any) {}

  Any any;
};

}  // namespace Carbon::SemIR

#endif  // CARBON_TOOLCHAIN_SEM_IR_TYPE_ITERATOR_H_


Review comment (refactor):
Why are these duplicated between `Step` and `TypeIterator`?

If you need distinct types, had you considered using inheritance to make it clear they're equivalent?

Code after:

  // A type value.
  struct ConcreteType {
    SemIR::TypeId type_id;
  };
  // A symbolic type value, constrained by `facet_type_id`.
  struct SymbolicType {
    // Either a FacetType or the TypeType singleton.
    SemIR::TypeId facet_type_id;
  };
  // A symbolic template type value.
  struct TemplateType {};
  // A concrete non-type value, which can be found as a generic parameter for a
  // type.
  struct ConcreteValue {
    // An instruction that evaluates to the constant value.
    SemIR::InstId inst_id;
  };
  // A symbolic non-type value, which can be found as a generic parameter for a
  // type.
  struct SymbolicValue {
    // An instruction that evaluates to the constant value.
    SemIR::InstId inst_id;
  };
  // A struct field name. The field names contribute to the type of the struct.
  struct StructFieldName {
    SemIR::NameId name_id;
  };

  // ===========================================================================
  // Results that report a state change in iteration.

  // Closes the scope of a `StartWithEnd`.
  struct End {};
  // Iteration is complete.
  struct Done {};

  // Each step is one of these.
  using Any = std::variant<ConcreteType, SymbolicType, TemplateType,
                           ConcreteValue, SymbolicValue, StructFieldName,
                           StartOnly, StartWithEnd, End, Done>;

  template <class T>
  auto Is() const -> bool {
    return std::holds_alternative<T>(any);
  }

  // Converts from any individual step.
  //
  // This is a template to allow implicit conversion directly from step values
  // that can go inside `Any` to `Step` (without having to make the `Any`