Repository: carbon-language/carbon-lang
File: toolchain/parse/node_ids.h (C/C++)

Code before:

// Aliases for `NodeIdInCategory` to describe particular categories of nodes.
using AnyDeclId = NodeIdInCategory<NodeCategory::Decl>;
using AnyExprId = NodeIdInCategory<NodeCategory::Expr>;
using AnyImplAsId = NodeIdInCategory<NodeCategory::ImplAs>;
using AnyMemberAccessId =
    NodeIdInCategory<NodeCategory::MemberName | NodeCategory::MemberExpr |
                     NodeCategory::IntConst>;
using AnyModifierId = NodeIdInCategory<NodeCategory::Modifier>;
using AnyPatternId = NodeIdInCategory<NodeCategory::Pattern>;
using AnyStatementId =
    NodeIdInCategory<NodeCategory::Statement | NodeCategory::Decl>;
using AnyRequireImplsId = NodeIdInCategory<NodeCategory::RequireImpls>;
using AnyRequirementId = NodeIdInCategory<NodeCategory::Requirement>;
using AnyNonExprNameId = NodeIdInCategory<NodeCategory::NonExprName>;
using AnyPackageNameId = NodeIdInCategory<NodeCategory::PackageName>;

template <typename T>
concept IsNodeKind = std::same_as<std::remove_cvref_t<T>, NodeKind> ||
                     std::same_as<std::remove_cvref_t<T>, NodeKind::Definition>;

template <typename T>
concept IsTypedNode = requires {
  { T::Kind } -> IsNodeKind;
};

// NodeId with kind that matches one of the `T::Kind`s.
template <typename... T>
  requires(sizeof...(T) >= 2 && (IsTypedNode<T> && ...))
struct NodeIdOneOf : public NodeId {
 private:
  // True if `OtherT` is one of `T`.
  template <typename OtherT>
  static constexpr bool Contains = (std::is_same<OtherT, T>{} || ...);

  // True if `NodeIdOneOf<SubsetT...>` is a subset of this `NodeIdOneOf`.
  template <typename Unused>
  static constexpr bool IsSubset = false;
  template <typename... SubsetT>
  static constexpr bool IsSubset<NodeIdOneOf<SubsetT...>> =
      (Contains<SubsetT> && ...);

  // Private to prevent accidental explicit construction from an untyped
  // NodeId.
  explicit constexpr NodeIdOneOf(NodeId node_id) : NodeId(node_id) {}

 public:
  // Provide a factory function for construction from `NodeId`. This doesn't
  // validate the type, so it's unsafe.
  static constexpr auto UnsafeMake(NodeId node_id) -> NodeIdOneOf {
    return NodeIdOneOf(node_id);

Review comment (suggestion):
Please put these in an `Internal` namespace. (Chandler has requested that we don't add concepts in our public API surface for evolution reasons.)

Code after:

// Aliases for `NodeIdInCategory` to describe particular categories of nodes.
using AnyDeclId = NodeIdInCategory<NodeCategory::Decl>;
using AnyExprId = NodeIdInCategory<NodeCategory::Expr>;
using AnyImplAsId = NodeIdInCategory<NodeCategory::ImplAs>;
using AnyMemberAccessId =
    NodeIdInCategory<NodeCategory::MemberName | NodeCategory::MemberExpr |
                     NodeCategory::IntConst>;
using AnyModifierId = NodeIdInCategory<NodeCategory::Modifier>;
using AnyPatternId = NodeIdInCategory<NodeCategory::Pattern>;
using AnyStatementId =
    NodeIdInCategory<NodeCategory::Statement | NodeCategory::Decl>;
using AnyRequireImplsId = NodeIdInCategory<NodeCategory::RequireImpls>;
using AnyRequirementId = NodeIdInCategory<NodeCategory::Requirement>;
using AnyNonExprNameId = NodeIdInCategory<NodeCategory::NonExprName>;
using AnyPackageNameId = NodeIdInCategory<NodeCategory::PackageName>;

namespace Internal {
template <typename T>
concept IsNodeKind = std::same_as<std::remove_cvref_t<T>, NodeKind> ||
                     std::same_as<std::remove_cvref_t<T>, NodeKind::Definition>;

template <typename T>
concept IsTypedNode = requires {
  { T::Kind } -> IsNodeKind;
};
}  // namespace Internal

// NodeId with kind that matches one of the `T::Kind`s.
template <typename... T>
  requires(sizeof...(T) >= 2 && (Internal::IsTypedNode<T> && ...))
struct NodeIdOneOf : public NodeId {
 private:
  // True if `OtherT` is one of `T`.
  template <typename OtherT>
  static constexpr bool Contains = (std::is_same<OtherT, T>{} || ...);

  // True if `NodeIdOneOf<SubsetT...>` is a subset of this `NodeIdOneOf`.
  template <typename Unused>
  static constexpr bool IsSubset = false;
  template <typename... SubsetT>
  static constexpr bool IsSubset<NodeIdOneOf<SubsetT...>> =
      (Contains<SubsetT> && ...);

  // Private to prevent accidental explicit construction from an untyped
  // NodeId.
  explicit constexpr NodeIdOneOf(NodeId node_id) : NodeId(node_id) {}

 public:
  // Provide a factory function for construction from `NodeId`. This doesn't
  // validate the type, so it's unsafe.