@@ -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,30 @@ 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 ( Interned < ModPath > ) ,
52
+ /// You can **not** rely on `Path::Normal` to not have generic args and type anchor, it may be missing both
53
+ /// (but generic args will be filled with `None`).
54
+ Normal ( NormalPath ) ,
59
55
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
60
56
/// links via a normal path since they might be private and not accessible in the usage place.
61
57
LangItem ( LangItemTarget , Option < Name > ) ,
62
58
}
63
59
60
+ // This type is being used a lot, make sure it doesn't grow unintentionally.
61
+ #[ cfg( target_arch = "x86_64" ) ]
62
+ const _: ( ) = {
63
+ assert ! ( size_of:: <Path >( ) == 16 ) ;
64
+ assert ! ( size_of:: <Option <Path >>( ) == 16 ) ;
65
+ } ;
66
+
67
+ thin_vec_with_header_struct ! {
68
+ pub new( pub ( crate ) ) struct NormalPath , NormalPathHeader {
69
+ pub generic_args: [ Option <GenericArgs >] ,
70
+ pub type_anchor: Option <TypeRefId >,
71
+ pub mod_path: Interned <ModPath >; ref,
72
+ }
73
+ }
74
+
64
75
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
65
76
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
66
77
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
@@ -112,50 +123,49 @@ impl Path {
112
123
}
113
124
114
125
/// 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
- }
126
+ pub fn from_known_path ( path : ModPath , generic_args : Vec < Option < GenericArgs > > ) -> Path {
127
+ Path :: Normal ( NormalPath :: new ( None , Interned :: new ( path) , generic_args) )
126
128
}
127
129
128
130
/// Converts a known mod path to `Path`.
129
131
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 }
132
+ Path :: BarePath ( Interned :: new ( path) )
131
133
}
132
134
135
+ #[ inline]
133
136
pub fn kind ( & self ) -> & PathKind {
134
137
match self {
135
- Path :: Normal { mod_path, .. } => & mod_path. kind ,
138
+ Path :: BarePath ( mod_path) => & mod_path. kind ,
139
+ Path :: Normal ( path) => & path. mod_path ( ) . kind ,
136
140
Path :: LangItem ( ..) => & PathKind :: Abs ,
137
141
}
138
142
}
139
143
144
+ #[ inline]
140
145
pub fn type_anchor ( & self ) -> Option < TypeRefId > {
141
146
match self {
142
- Path :: Normal { type_anchor, .. } => * type_anchor,
143
- Path :: LangItem ( ..) => None ,
147
+ Path :: Normal ( path) => path. type_anchor ( ) ,
148
+ Path :: LangItem ( ..) | Path :: BarePath ( _) => None ,
149
+ }
150
+ }
151
+
152
+ #[ inline]
153
+ pub fn generic_args ( & self ) -> Option < & [ Option < GenericArgs > ] > {
154
+ match self {
155
+ Path :: Normal ( path) => Some ( path. generic_args ( ) ) ,
156
+ Path :: LangItem ( ..) | Path :: BarePath ( _) => None ,
144
157
}
145
158
}
146
159
147
160
pub fn segments ( & self ) -> PathSegments < ' _ > {
148
161
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
162
+ Path :: BarePath ( mod_path) => {
163
+ PathSegments { segments : mod_path. segments ( ) , generic_args : None }
158
164
}
165
+ Path :: Normal ( path) => PathSegments {
166
+ segments : path. mod_path ( ) . segments ( ) ,
167
+ generic_args : Some ( path. generic_args ( ) ) ,
168
+ } ,
159
169
Path :: LangItem ( _, seg) => PathSegments {
160
170
segments : seg. as_ref ( ) . map_or ( & [ ] , |seg| std:: slice:: from_ref ( seg) ) ,
161
171
generic_args : None ,
@@ -165,34 +175,55 @@ impl Path {
165
175
166
176
pub fn mod_path ( & self ) -> Option < & ModPath > {
167
177
match self {
168
- Path :: Normal { mod_path, .. } => Some ( mod_path) ,
178
+ Path :: BarePath ( mod_path) => Some ( mod_path) ,
179
+ Path :: Normal ( path) => Some ( path. mod_path ( ) ) ,
169
180
Path :: LangItem ( ..) => None ,
170
181
}
171
182
}
172
183
173
184
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 ;
185
+ match self {
186
+ Path :: BarePath ( mod_path) => {
187
+ if mod_path. is_ident ( ) {
188
+ return None ;
189
+ }
190
+ Some ( Path :: BarePath ( Interned :: new ( ModPath :: from_segments (
191
+ mod_path. kind ,
192
+ mod_path. segments ( ) [ ..mod_path. segments ( ) . len ( ) - 1 ] . iter ( ) . cloned ( ) ,
193
+ ) ) ) )
194
+ }
195
+ Path :: Normal ( path) => {
196
+ let mod_path = path. mod_path ( ) ;
197
+ if mod_path. is_ident ( ) {
198
+ return None ;
199
+ }
200
+ let type_anchor = path. type_anchor ( ) ;
201
+ let generic_args = path. generic_args ( ) ;
202
+ let qualifier_mod_path = Interned :: new ( ModPath :: from_segments (
203
+ mod_path. kind ,
204
+ mod_path. segments ( ) [ ..mod_path. segments ( ) . len ( ) - 1 ] . iter ( ) . cloned ( ) ,
205
+ ) ) ;
206
+ let qualifier_generic_args = & generic_args[ ..generic_args. len ( ) - 1 ] ;
207
+ Some ( Path :: Normal ( NormalPath :: new (
208
+ type_anchor,
209
+ qualifier_mod_path,
210
+ qualifier_generic_args. iter ( ) . cloned ( ) ,
211
+ ) ) )
212
+ }
213
+ Path :: LangItem ( ..) => None ,
179
214
}
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
215
}
190
216
191
217
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 ( )
218
+ match self {
219
+ Path :: BarePath ( mod_path) => mod_path. is_Self ( ) ,
220
+ Path :: Normal ( path) => {
221
+ path. type_anchor ( ) . is_none ( )
222
+ && path. mod_path ( ) . is_Self ( )
223
+ && path. generic_args ( ) . iter ( ) . all ( |args| args. is_none ( ) )
224
+ }
225
+ Path :: LangItem ( ..) => false ,
226
+ }
196
227
}
197
228
}
198
229
@@ -268,16 +299,6 @@ impl GenericArgs {
268
299
269
300
impl From < Name > for Path {
270
301
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) )
302
+ Path :: BarePath ( Interned :: new ( ModPath :: from_segments ( PathKind :: Plain , iter:: once ( name) ) ) )
282
303
}
283
304
}
0 commit comments