@@ -17,13 +17,31 @@ use crate::{
17
17
type_ref:: { LifetimeRef , TypeBound , TypeRef } ,
18
18
} ;
19
19
20
+ #[ cfg( test) ]
21
+ thread_local ! {
22
+ /// This is used to test `hir_segment_to_ast_segment()`. It's a hack, but it makes testing much easier.
23
+ pub ( super ) static SEGMENT_LOWERING_MAP : std:: cell:: RefCell <rustc_hash:: FxHashMap <ast:: PathSegment , usize >> = std:: cell:: RefCell :: default ( ) ;
24
+ }
25
+
20
26
/// Converts an `ast::Path` to `Path`. Works with use trees.
21
27
/// It correctly handles `$crate` based path from macro call.
28
+ // If you modify the logic of the lowering, make sure to check if `hir_segment_to_ast_segment()`
29
+ // also needs an update.
22
30
pub ( super ) fn lower_path ( ctx : & mut LowerCtx < ' _ > , mut path : ast:: Path ) -> Option < Path > {
23
31
let mut kind = PathKind :: Plain ;
24
32
let mut type_anchor = None ;
25
33
let mut segments = Vec :: new ( ) ;
26
34
let mut generic_args = Vec :: new ( ) ;
35
+ #[ cfg( test) ]
36
+ let mut ast_segments = Vec :: new ( ) ;
37
+ #[ cfg( test) ]
38
+ let mut ast_segments_offset = 0 ;
39
+ #[ allow( unused_mut) ]
40
+ let mut push_segment = |_segment : & ast:: PathSegment , segments : & mut Vec < Name > , name| {
41
+ #[ cfg( test) ]
42
+ ast_segments. push ( _segment. clone ( ) ) ;
43
+ segments. push ( name) ;
44
+ } ;
27
45
loop {
28
46
let segment = path. segment ( ) ?;
29
47
@@ -34,6 +52,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
34
52
match segment. kind ( ) ? {
35
53
ast:: PathSegmentKind :: Name ( name_ref) => {
36
54
if name_ref. text ( ) == "$crate" {
55
+ if path. qualifier ( ) . is_some ( ) {
56
+ // FIXME: Report an error.
57
+ return None ;
58
+ }
37
59
break kind = resolve_crate_root (
38
60
ctx. db . upcast ( ) ,
39
61
ctx. span_map ( ) . span_for_range ( name_ref. syntax ( ) . text_range ( ) ) . ctx ,
@@ -56,10 +78,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
56
78
generic_args. resize ( segments. len ( ) , None ) ;
57
79
generic_args. push ( args) ;
58
80
}
59
- segments . push ( name) ;
81
+ push_segment ( & segment , & mut segments , name) ;
60
82
}
61
83
ast:: PathSegmentKind :: SelfTypeKw => {
62
- segments . push ( Name :: new_symbol_root ( sym:: Self_ . clone ( ) ) ) ;
84
+ push_segment ( & segment , & mut segments , Name :: new_symbol_root ( sym:: Self_ . clone ( ) ) ) ;
63
85
}
64
86
ast:: PathSegmentKind :: Type { type_ref, trait_ref } => {
65
87
assert ! ( path. qualifier( ) . is_none( ) ) ; // this can only occur at the first segment
@@ -81,6 +103,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
81
103
kind = mod_path. kind ;
82
104
83
105
segments. extend ( mod_path. segments ( ) . iter ( ) . cloned ( ) . rev ( ) ) ;
106
+ #[ cfg( test) ]
107
+ {
108
+ ast_segments_offset = mod_path. segments ( ) . len ( ) ;
109
+ }
84
110
if let Some ( path_generic_args) = path_generic_args {
85
111
generic_args. resize ( segments. len ( ) - num_segments, None ) ;
86
112
generic_args. extend ( Vec :: from ( path_generic_args) . into_iter ( ) . rev ( ) ) ;
@@ -112,10 +138,18 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
112
138
}
113
139
}
114
140
ast:: PathSegmentKind :: CrateKw => {
141
+ if path. qualifier ( ) . is_some ( ) {
142
+ // FIXME: Report an error.
143
+ return None ;
144
+ }
115
145
kind = PathKind :: Crate ;
116
146
break ;
117
147
}
118
148
ast:: PathSegmentKind :: SelfKw => {
149
+ if path. qualifier ( ) . is_some ( ) {
150
+ // FIXME: Report an error.
151
+ return None ;
152
+ }
119
153
// don't break out if `self` is the last segment of a path, this mean we got a
120
154
// use tree like `foo::{self}` which we want to resolve as `foo`
121
155
if !segments. is_empty ( ) {
@@ -162,6 +196,13 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
162
196
}
163
197
}
164
198
199
+ #[ cfg( test) ]
200
+ {
201
+ ast_segments. reverse ( ) ;
202
+ SEGMENT_LOWERING_MAP
203
+ . with_borrow_mut ( |map| map. extend ( ast_segments. into_iter ( ) . zip ( ast_segments_offset..) ) ) ;
204
+ }
205
+
165
206
let mod_path = Interned :: new ( ModPath :: from_segments ( kind, segments) ) ;
166
207
if type_anchor. is_none ( ) && generic_args. is_empty ( ) {
167
208
return Some ( Path :: BarePath ( mod_path) ) ;
@@ -181,6 +222,41 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
181
222
}
182
223
}
183
224
225
+ /// This function finds the AST segment that corresponds to the HIR segment
226
+ /// with index `segment_idx` on the path that is lowered from `path`.
227
+ pub fn hir_segment_to_ast_segment ( path : & ast:: Path , segment_idx : u32 ) -> Option < ast:: PathSegment > {
228
+ // Too tightly coupled to `lower_path()`, but unfortunately we cannot decouple them,
229
+ // as keeping source maps for all paths segments will have a severe impact on memory usage.
230
+
231
+ let mut segments = path. segments ( ) ;
232
+ if let Some ( ast:: PathSegmentKind :: Type { trait_ref : Some ( trait_ref) , .. } ) =
233
+ segments. clone ( ) . next ( ) . and_then ( |it| it. kind ( ) )
234
+ {
235
+ segments. next ( ) ;
236
+ return find_segment ( trait_ref. path ( ) ?. segments ( ) . chain ( segments) , segment_idx) ;
237
+ }
238
+ return find_segment ( segments, segment_idx) ;
239
+
240
+ fn find_segment (
241
+ segments : impl Iterator < Item = ast:: PathSegment > ,
242
+ segment_idx : u32 ,
243
+ ) -> Option < ast:: PathSegment > {
244
+ segments
245
+ . filter ( |segment| match segment. kind ( ) {
246
+ Some (
247
+ ast:: PathSegmentKind :: CrateKw
248
+ | ast:: PathSegmentKind :: SelfKw
249
+ | ast:: PathSegmentKind :: SuperKw
250
+ | ast:: PathSegmentKind :: Type { .. } ,
251
+ )
252
+ | None => false ,
253
+ Some ( ast:: PathSegmentKind :: Name ( name) ) => name. text ( ) != "$crate" ,
254
+ Some ( ast:: PathSegmentKind :: SelfTypeKw ) => true ,
255
+ } )
256
+ . nth ( segment_idx as usize )
257
+ }
258
+ }
259
+
184
260
pub ( super ) fn lower_generic_args (
185
261
lower_ctx : & mut LowerCtx < ' _ > ,
186
262
node : ast:: GenericArgList ,
0 commit comments