@@ -14,6 +14,7 @@ use crate::{
14
14
use hir_expand:: name:: Name ;
15
15
use intern:: Interned ;
16
16
use span:: Edition ;
17
+ use stdx:: thin_vec:: thin_vec_with_header_struct;
17
18
use syntax:: ast;
18
19
19
20
pub use hir_expand:: mod_path:: { path, ModPath , PathKind } ;
@@ -47,20 +48,33 @@ impl Display for ImportAliasDisplay<'_> {
47
48
48
49
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
49
50
pub 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 ) ,
59
58
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
60
59
/// links via a normal path since they might be private and not accessible in the usage place.
61
60
LangItem ( LangItemTarget , Option < Name > ) ,
62
61
}
63
62
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
+
64
78
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
65
79
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
66
80
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
@@ -112,50 +126,49 @@ impl Path {
112
126
}
113
127
114
128
/// 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) )
126
131
}
127
132
128
133
/// Converts a known mod path to `Path`.
129
134
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) )
131
136
}
132
137
138
+ #[ inline]
133
139
pub fn kind ( & self ) -> & PathKind {
134
140
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 ,
136
143
Path :: LangItem ( ..) => & PathKind :: Abs ,
137
144
}
138
145
}
139
146
147
+ #[ inline]
140
148
pub fn type_anchor ( & self ) -> Option < TypeRefId > {
141
149
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 ,
144
160
}
145
161
}
146
162
147
163
pub fn segments ( & self ) -> PathSegments < ' _ > {
148
164
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 }
158
167
}
168
+ Path :: Normal ( path) => PathSegments {
169
+ segments : path. mod_path ( ) . segments ( ) ,
170
+ generic_args : Some ( path. generic_args ( ) ) ,
171
+ } ,
159
172
Path :: LangItem ( _, seg) => PathSegments {
160
173
segments : seg. as_ref ( ) . map_or ( & [ ] , |seg| std:: slice:: from_ref ( seg) ) ,
161
174
generic_args : None ,
@@ -165,34 +178,55 @@ impl Path {
165
178
166
179
pub fn mod_path ( & self ) -> Option < & ModPath > {
167
180
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 ( ) ) ,
169
183
Path :: LangItem ( ..) => None ,
170
184
}
171
185
}
172
186
173
187
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 ,
179
217
}
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)
189
218
}
190
219
191
220
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
+ }
196
230
}
197
231
}
198
232
@@ -268,16 +302,6 @@ impl GenericArgs {
268
302
269
303
impl From < Name > for Path {
270
304
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) ) ) )
282
306
}
283
307
}
0 commit comments