@@ -17,13 +17,31 @@ use crate::{
1717 type_ref:: { LifetimeRef , TypeBound , TypeRef } ,
1818} ;
1919
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+
2026/// Converts an `ast::Path` to `Path`. Works with use trees.
2127/// 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.
2230pub ( super ) fn lower_path ( ctx : & mut LowerCtx < ' _ > , mut path : ast:: Path ) -> Option < Path > {
2331 let mut kind = PathKind :: Plain ;
2432 let mut type_anchor = None ;
2533 let mut segments = Vec :: new ( ) ;
2634 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+ } ;
2745 loop {
2846 let segment = path. segment ( ) ?;
2947
@@ -34,6 +52,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
3452 match segment. kind ( ) ? {
3553 ast:: PathSegmentKind :: Name ( name_ref) => {
3654 if name_ref. text ( ) == "$crate" {
55+ if path. qualifier ( ) . is_some ( ) {
56+ // FIXME: Report an error.
57+ return None ;
58+ }
3759 break kind = resolve_crate_root (
3860 ctx. db . upcast ( ) ,
3961 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<
5678 generic_args. resize ( segments. len ( ) , None ) ;
5779 generic_args. push ( args) ;
5880 }
59- segments . push ( name) ;
81+ push_segment ( & segment , & mut segments , name) ;
6082 }
6183 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 ( ) ) ) ;
6385 }
6486 ast:: PathSegmentKind :: Type { type_ref, trait_ref } => {
6587 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<
81103 kind = mod_path. kind ;
82104
83105 segments. extend ( mod_path. segments ( ) . iter ( ) . cloned ( ) . rev ( ) ) ;
106+ #[ cfg( test) ]
107+ {
108+ ast_segments_offset = mod_path. segments ( ) . len ( ) ;
109+ }
84110 if let Some ( path_generic_args) = path_generic_args {
85111 generic_args. resize ( segments. len ( ) - num_segments, None ) ;
86112 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<
112138 }
113139 }
114140 ast:: PathSegmentKind :: CrateKw => {
141+ if path. qualifier ( ) . is_some ( ) {
142+ // FIXME: Report an error.
143+ return None ;
144+ }
115145 kind = PathKind :: Crate ;
116146 break ;
117147 }
118148 ast:: PathSegmentKind :: SelfKw => {
149+ if path. qualifier ( ) . is_some ( ) {
150+ // FIXME: Report an error.
151+ return None ;
152+ }
119153 // don't break out if `self` is the last segment of a path, this mean we got a
120154 // use tree like `foo::{self}` which we want to resolve as `foo`
121155 if !segments. is_empty ( ) {
@@ -162,6 +196,13 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
162196 }
163197 }
164198
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+
165206 let mod_path = Interned :: new ( ModPath :: from_segments ( kind, segments) ) ;
166207 if type_anchor. is_none ( ) && generic_args. is_empty ( ) {
167208 return Some ( Path :: BarePath ( mod_path) ) ;
@@ -181,6 +222,41 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
181222 }
182223}
183224
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+
184260pub ( super ) fn lower_generic_args (
185261 lower_ctx : & mut LowerCtx < ' _ > ,
186262 node : ast:: GenericArgList ,
0 commit comments