@@ -40,9 +40,20 @@ template <const NodeKind& K>
4040struct NodeIdForKind : public NodeId {
4141 // NOLINTNEXTLINE(readability-identifier-naming)
4242 static const NodeKind& Kind;
43- constexpr explicit NodeIdForKind (NodeId node_id) : NodeId(node_id) {}
43+
44+ // Provide a factory function for construction from `NodeId`. This doesn't
45+ // validate the type, so it's unsafe.
46+ static constexpr auto UnsafeMake (NodeId node_id) -> NodeIdForKind {
47+ return NodeIdForKind (node_id);
48+ }
49+
4450 // NOLINTNEXTLINE(google-explicit-constructor)
4551 constexpr NodeIdForKind (NoneNodeId /* none*/ ) : NodeId(NoneIndex) {}
52+
53+ private:
54+ // Private to prevent accidental explicit construction from an untyped
55+ // NodeId.
56+ explicit constexpr NodeIdForKind (NodeId node_id) : NodeId(node_id) {}
4657};
4758template <const NodeKind& K>
4859const NodeKind& NodeIdForKind<K>::Kind = K;
@@ -54,6 +65,12 @@ const NodeKind& NodeIdForKind<K>::Kind = K;
5465// NodeId that matches any NodeKind whose `category()` overlaps with `Category`.
5566template <NodeCategory::RawEnumType Category>
5667struct NodeIdInCategory : public NodeId {
68+ // Provide a factory function for construction from `NodeId`. This doesn't
69+ // validate the type, so it's unsafe.
70+ static constexpr auto UnsafeMake (NodeId node_id) -> NodeIdInCategory {
71+ return NodeIdInCategory (node_id);
72+ }
73+
5774 // Support conversion from `NodeIdForKind<Kind>` if Kind's category
5875 // overlaps with `Category`.
5976 template <const NodeKind& Kind>
@@ -62,9 +79,13 @@ struct NodeIdInCategory : public NodeId {
6279 CARBON_CHECK (Kind.category ().HasAnyOf (Category));
6380 }
6481
65- constexpr explicit NodeIdInCategory (NodeId node_id) : NodeId(node_id) {}
6682 // NOLINTNEXTLINE(google-explicit-constructor)
6783 constexpr NodeIdInCategory (NoneNodeId /* none*/ ) : NodeId(NoneIndex) {}
84+
85+ private:
86+ // Private to prevent accidental explicit construction from an untyped
87+ // NodeId.
88+ explicit constexpr NodeIdInCategory (NodeId node_id) : NodeId(node_id) {}
6889};
6990
7091// Aliases for `NodeIdInCategory` to describe particular categories of nodes.
@@ -84,16 +105,26 @@ using AnyPackageNameId = NodeIdInCategory<NodeCategory::PackageName>;
84105
85106// NodeId with kind that matches one of the `T::Kind`s.
86107template <typename ... T>
108+ requires (sizeof ...(T) >= 2 )
87109struct NodeIdOneOf : public NodeId {
88- static_assert (sizeof ...(T) >= 2 , " Expected at least two types." );
89- constexpr explicit NodeIdOneOf (NodeId node_id) : NodeId(node_id) {}
110+ // Provide a factory function for construction from `NodeId`. This doesn't
111+ // validate the type, so it's unsafe.
112+ static constexpr auto UnsafeMake (NodeId node_id) -> NodeIdOneOf {
113+ return NodeIdOneOf (node_id);
114+ }
115+
90116 template <const NodeKind& Kind>
117+ requires ((T::Kind == Kind) || ...)
91118 // NOLINTNEXTLINE(google-explicit-constructor)
92- NodeIdOneOf (NodeIdForKind<Kind> node_id) : NodeId(node_id) {
93- static_assert (((T::Kind == Kind) || ...));
94- }
119+ NodeIdOneOf (NodeIdForKind<Kind> node_id) : NodeId(node_id) {}
120+
95121 // NOLINTNEXTLINE(google-explicit-constructor)
96122 constexpr NodeIdOneOf (NoneNodeId /* none*/ ) : NodeId(NoneIndex) {}
123+
124+ private:
125+ // Private to prevent accidental explicit construction from an untyped
126+ // NodeId.
127+ explicit constexpr NodeIdOneOf (NodeId node_id) : NodeId(node_id) {}
97128};
98129
99130using AnyClassDeclId =
0 commit comments