@@ -14,6 +14,7 @@ use crate::{
1414use hir_expand:: name:: Name ;
1515use intern:: Interned ;
1616use span:: Edition ;
17+ use stdx:: thin_vec:: thin_vec_with_header_struct;
1718use syntax:: ast;
1819
1920pub use hir_expand:: mod_path:: { path, ModPath , PathKind } ;
@@ -47,20 +48,33 @@ impl Display for ImportAliasDisplay<'_> {
4748
4849#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
4950pub enum Path {
50- /// A normal path
51- Normal {
52- /// Type based path like `<T>::foo`.
53- /// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
54- type_anchor : Option < TypeRefId > ,
55- mod_path : Interned < ModPath > ,
56- /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
57- generic_args : Option < Box < [ Option < GenericArgs > ] > > ,
58- } ,
51+ /// `BarePath` is used when the path has neither generics nor type anchor, since the vast majority of paths
52+ /// are in this category, and splitting `Path` this way allows it to be more thin. When the path has either generics
53+ /// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically
54+ /// this is not a problem since many more paths have generics than a type anchor).
55+ BarePath ( Interned < ModPath > ) ,
56+ /// `Path::Normal` may have empty generics and type anchor (but generic args will be filled with `None`).
57+ Normal ( NormalPath ) ,
5958 /// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
6059 /// links via a normal path since they might be private and not accessible in the usage place.
6160 LangItem ( LangItemTarget , Option < Name > ) ,
6261}
6362
63+ // This type is being used a lot, make sure it doesn't grow unintentionally.
64+ #[ cfg( target_arch = "x86_64" ) ]
65+ const _: ( ) = {
66+ assert ! ( size_of:: <Path >( ) == 16 ) ;
67+ assert ! ( size_of:: <Option <Path >>( ) == 16 ) ;
68+ } ;
69+
70+ thin_vec_with_header_struct ! {
71+ pub new( pub ( crate ) ) struct NormalPath , NormalPathHeader {
72+ pub generic_args: [ Option <GenericArgs >] ,
73+ pub type_anchor: Option <TypeRefId >,
74+ pub mod_path: Interned <ModPath >; ref,
75+ }
76+ }
77+
6478/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
6579/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
6680#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
@@ -112,50 +126,49 @@ impl Path {
112126 }
113127
114128 /// Converts a known mod path to `Path`.
115- pub fn from_known_path (
116- path : ModPath ,
117- generic_args : impl Into < Box < [ Option < GenericArgs > ] > > ,
118- ) -> Path {
119- let generic_args = generic_args. into ( ) ;
120- assert_eq ! ( path. len( ) , generic_args. len( ) ) ;
121- Path :: Normal {
122- type_anchor : None ,
123- mod_path : Interned :: new ( path) ,
124- generic_args : Some ( generic_args) ,
125- }
129+ pub fn from_known_path ( path : ModPath , generic_args : Vec < Option < GenericArgs > > ) -> Path {
130+ Path :: Normal ( NormalPath :: new ( None , Interned :: new ( path) , generic_args) )
126131 }
127132
128133 /// Converts a known mod path to `Path`.
129134 pub fn from_known_path_with_no_generic ( path : ModPath ) -> Path {
130- Path :: Normal { type_anchor : None , mod_path : Interned :: new ( path) , generic_args : None }
135+ Path :: BarePath ( Interned :: new ( path) )
131136 }
132137
138+ #[ inline]
133139 pub fn kind ( & self ) -> & PathKind {
134140 match self {
135- Path :: Normal { mod_path, .. } => & mod_path. kind ,
141+ Path :: BarePath ( mod_path) => & mod_path. kind ,
142+ Path :: Normal ( path) => & path. mod_path ( ) . kind ,
136143 Path :: LangItem ( ..) => & PathKind :: Abs ,
137144 }
138145 }
139146
147+ #[ inline]
140148 pub fn type_anchor ( & self ) -> Option < TypeRefId > {
141149 match self {
142- Path :: Normal { type_anchor, .. } => * type_anchor,
143- Path :: LangItem ( ..) => None ,
150+ Path :: Normal ( path) => path. type_anchor ( ) ,
151+ Path :: LangItem ( ..) | Path :: BarePath ( _) => None ,
152+ }
153+ }
154+
155+ #[ inline]
156+ pub fn generic_args ( & self ) -> Option < & [ Option < GenericArgs > ] > {
157+ match self {
158+ Path :: Normal ( path) => Some ( path. generic_args ( ) ) ,
159+ Path :: LangItem ( ..) | Path :: BarePath ( _) => None ,
144160 }
145161 }
146162
147163 pub fn segments ( & self ) -> PathSegments < ' _ > {
148164 match self {
149- Path :: Normal { mod_path, generic_args, .. } => {
150- let s = PathSegments {
151- segments : mod_path. segments ( ) ,
152- generic_args : generic_args. as_deref ( ) ,
153- } ;
154- if let Some ( generic_args) = s. generic_args {
155- assert_eq ! ( s. segments. len( ) , generic_args. len( ) ) ;
156- }
157- s
165+ Path :: BarePath ( mod_path) => {
166+ PathSegments { segments : mod_path. segments ( ) , generic_args : None }
158167 }
168+ Path :: Normal ( path) => PathSegments {
169+ segments : path. mod_path ( ) . segments ( ) ,
170+ generic_args : Some ( path. generic_args ( ) ) ,
171+ } ,
159172 Path :: LangItem ( _, seg) => PathSegments {
160173 segments : seg. as_ref ( ) . map_or ( & [ ] , |seg| std:: slice:: from_ref ( seg) ) ,
161174 generic_args : None ,
@@ -165,34 +178,55 @@ impl Path {
165178
166179 pub fn mod_path ( & self ) -> Option < & ModPath > {
167180 match self {
168- Path :: Normal { mod_path, .. } => Some ( mod_path) ,
181+ Path :: BarePath ( mod_path) => Some ( mod_path) ,
182+ Path :: Normal ( path) => Some ( path. mod_path ( ) ) ,
169183 Path :: LangItem ( ..) => None ,
170184 }
171185 }
172186
173187 pub fn qualifier ( & self ) -> Option < Path > {
174- let Path :: Normal { mod_path, generic_args, type_anchor } = self else {
175- return None ;
176- } ;
177- if mod_path. is_ident ( ) {
178- return None ;
188+ match self {
189+ Path :: BarePath ( mod_path) => {
190+ if mod_path. is_ident ( ) {
191+ return None ;
192+ }
193+ Some ( Path :: BarePath ( Interned :: new ( ModPath :: from_segments (
194+ mod_path. kind ,
195+ mod_path. segments ( ) [ ..mod_path. segments ( ) . len ( ) - 1 ] . iter ( ) . cloned ( ) ,
196+ ) ) ) )
197+ }
198+ Path :: Normal ( path) => {
199+ let mod_path = path. mod_path ( ) ;
200+ if mod_path. is_ident ( ) {
201+ return None ;
202+ }
203+ let type_anchor = path. type_anchor ( ) ;
204+ let generic_args = path. generic_args ( ) ;
205+ let qualifier_mod_path = Interned :: new ( ModPath :: from_segments (
206+ mod_path. kind ,
207+ mod_path. segments ( ) [ ..mod_path. segments ( ) . len ( ) - 1 ] . iter ( ) . cloned ( ) ,
208+ ) ) ;
209+ let qualifier_generic_args = & generic_args[ ..generic_args. len ( ) - 1 ] ;
210+ Some ( Path :: Normal ( NormalPath :: new (
211+ type_anchor,
212+ qualifier_mod_path,
213+ qualifier_generic_args. iter ( ) . cloned ( ) ,
214+ ) ) )
215+ }
216+ Path :: LangItem ( ..) => None ,
179217 }
180- let res = Path :: Normal {
181- type_anchor : * type_anchor,
182- mod_path : Interned :: new ( ModPath :: from_segments (
183- mod_path. kind ,
184- mod_path. segments ( ) [ ..mod_path. segments ( ) . len ( ) - 1 ] . iter ( ) . cloned ( ) ,
185- ) ) ,
186- generic_args : generic_args. as_ref ( ) . map ( |it| it[ ..it. len ( ) - 1 ] . to_vec ( ) . into ( ) ) ,
187- } ;
188- Some ( res)
189218 }
190219
191220 pub fn is_self_type ( & self ) -> bool {
192- let Path :: Normal { mod_path, generic_args, type_anchor } = self else {
193- return false ;
194- } ;
195- type_anchor. is_none ( ) && generic_args. as_deref ( ) . is_none ( ) && mod_path. is_Self ( )
221+ match self {
222+ Path :: BarePath ( mod_path) => mod_path. is_Self ( ) ,
223+ Path :: Normal ( path) => {
224+ path. type_anchor ( ) . is_none ( )
225+ && path. mod_path ( ) . is_Self ( )
226+ && path. generic_args ( ) . iter ( ) . all ( |args| args. is_none ( ) )
227+ }
228+ Path :: LangItem ( ..) => false ,
229+ }
196230 }
197231}
198232
@@ -268,16 +302,6 @@ impl GenericArgs {
268302
269303impl From < Name > for Path {
270304 fn from ( name : Name ) -> Path {
271- Path :: Normal {
272- type_anchor : None ,
273- mod_path : Interned :: new ( ModPath :: from_segments ( PathKind :: Plain , iter:: once ( name) ) ) ,
274- generic_args : None ,
275- }
276- }
277- }
278-
279- impl From < Name > for Box < Path > {
280- fn from ( name : Name ) -> Box < Path > {
281- Box :: new ( Path :: from ( name) )
305+ Path :: BarePath ( Interned :: new ( ModPath :: from_segments ( PathKind :: Plain , iter:: once ( name) ) ) )
282306 }
283307}
0 commit comments