11//! Expansion of associated items
22
3- use hir_expand:: {
4- AstId , ExpandResult , InFile , Intern , Lookup , MacroCallKind , MacroDefKind , name:: Name ,
5- } ;
6- use smallvec:: SmallVec ;
7- use span:: { HirFileId , MacroCallId } ;
8- use syntax:: { Parse , ast} ;
3+ use hir_expand:: { AstId , InFile , Intern , Lookup , MacroCallKind , MacroDefKind , name:: Name } ;
4+ use span:: MacroCallId ;
5+ use syntax:: ast;
96use triomphe:: Arc ;
107
118use crate :: {
129 AssocItemId , AstIdWithPath , ConstLoc , FunctionId , FunctionLoc , ImplId , ItemContainerId ,
1310 ItemLoc , ModuleId , TraitId , TypeAliasId , TypeAliasLoc ,
1411 db:: DefDatabase ,
15- expander:: { Expander , Mark } ,
16- item_tree:: { self , AssocItem , ItemTree , ItemTreeId , MacroCall , ModItem , TreeId } ,
12+ item_tree:: { AssocItem , ItemTree , ItemTreeId , MacroCall , ModItem , TreeId } ,
1713 macro_call_as_call_id,
1814 nameres:: {
1915 DefMap , LocalDefMap , MacroSubNs ,
@@ -26,6 +22,7 @@ use crate::{
2622pub struct TraitItems {
2723 pub items : Box < [ ( Name , AssocItemId ) ] > ,
2824 // box it as the vec is usually empty anyways
25+ // FIXME: AstIds are rather unstable...
2926 pub macro_calls : Option < Box < Vec < ( AstId < ast:: Item > , MacroCallId ) > > > ,
3027}
3128
@@ -40,13 +37,11 @@ impl TraitItems {
4037 tr : TraitId ,
4138 ) -> ( Arc < TraitItems > , DefDiagnostics ) {
4239 let ItemLoc { container : module_id, id : tree_id } = tr. lookup ( db) ;
43- let item_tree = tree_id. item_tree ( db) ;
44- let tr_def = & item_tree[ tree_id. value ] ;
4540
46- let mut collector =
47- AssocItemCollector :: new ( db , module_id , tree_id. file_id ( ) , ItemContainerId :: TraitId ( tr ) ) ;
48- collector . collect ( & item_tree , tree_id . tree_id ( ) , & tr_def . items ) ;
49- let ( items , macro_calls , diagnostics ) = collector. finish ( ) ;
41+ let collector = AssocItemCollector :: new ( db , module_id , ItemContainerId :: TraitId ( tr ) ) ;
42+ let item_tree = tree_id. item_tree ( db ) ;
43+ let ( items , macro_calls , diagnostics ) =
44+ collector. collect ( & item_tree , tree_id . tree_id ( ) , & item_tree [ tree_id . value ] . items ) ;
5045
5146 ( Arc :: new ( TraitItems { macro_calls, items } ) , DefDiagnostics :: new ( diagnostics) )
5247 }
@@ -81,6 +76,7 @@ impl TraitItems {
8176pub struct ImplItems {
8277 pub items : Box < [ ( Name , AssocItemId ) ] > ,
8378 // box it as the vec is usually empty anyways
79+ // FIXME: AstIds are rather unstable...
8480 pub macro_calls : Option < Box < Vec < ( AstId < ast:: Item > , MacroCallId ) > > > ,
8581}
8682
@@ -97,13 +93,10 @@ impl ImplItems {
9793 let _p = tracing:: info_span!( "impl_items_with_diagnostics_query" ) . entered ( ) ;
9894 let ItemLoc { container : module_id, id : tree_id } = id. lookup ( db) ;
9995
96+ let collector = AssocItemCollector :: new ( db, module_id, ItemContainerId :: ImplId ( id) ) ;
10097 let item_tree = tree_id. item_tree ( db) ;
101- let impl_def = & item_tree[ tree_id. value ] ;
102- let mut collector =
103- AssocItemCollector :: new ( db, module_id, tree_id. file_id ( ) , ItemContainerId :: ImplId ( id) ) ;
104- collector. collect ( & item_tree, tree_id. tree_id ( ) , & impl_def. items ) ;
105-
106- let ( items, macro_calls, diagnostics) = collector. finish ( ) ;
98+ let ( items, macro_calls, diagnostics) =
99+ collector. collect ( & item_tree, tree_id. tree_id ( ) , & item_tree[ tree_id. value ] . items ) ;
107100
108101 ( Arc :: new ( ImplItems { items, macro_calls } ) , DefDiagnostics :: new ( diagnostics) )
109102 }
@@ -120,157 +113,143 @@ struct AssocItemCollector<'a> {
120113 local_def_map : Arc < LocalDefMap > ,
121114 diagnostics : Vec < DefDiagnostic > ,
122115 container : ItemContainerId ,
123- expander : Expander ,
124116
117+ depth : usize ,
125118 items : Vec < ( Name , AssocItemId ) > ,
126119 macro_calls : Vec < ( AstId < ast:: Item > , MacroCallId ) > ,
127120}
128121
129122impl < ' a > AssocItemCollector < ' a > {
130- fn new (
131- db : & ' a dyn DefDatabase ,
132- module_id : ModuleId ,
133- file_id : HirFileId ,
134- container : ItemContainerId ,
135- ) -> Self {
123+ fn new ( db : & ' a dyn DefDatabase , module_id : ModuleId , container : ItemContainerId ) -> Self {
136124 let ( def_map, local_def_map) = module_id. local_def_map ( db) ;
137125 Self {
138126 db,
139127 module_id,
140128 def_map,
141129 local_def_map,
142130 container,
143- expander : Expander :: new ( db, file_id, module_id) ,
144131 items : Vec :: new ( ) ,
132+
133+ depth : 0 ,
145134 macro_calls : Vec :: new ( ) ,
146135 diagnostics : Vec :: new ( ) ,
147136 }
148137 }
149138
150- fn finish (
151- self ,
139+ fn collect (
140+ mut self ,
141+ item_tree : & ItemTree ,
142+ tree_id : TreeId ,
143+ assoc_items : & [ AssocItem ] ,
152144 ) -> (
153145 Box < [ ( Name , AssocItemId ) ] > ,
154146 Option < Box < Vec < ( AstId < ast:: Item > , MacroCallId ) > > > ,
155147 Vec < DefDiagnostic > ,
156148 ) {
149+ self . items . reserve ( assoc_items. len ( ) ) ;
150+ for & item in assoc_items {
151+ self . collect_item ( item_tree, tree_id, item) ;
152+ }
157153 (
158154 self . items . into_boxed_slice ( ) ,
159155 if self . macro_calls . is_empty ( ) { None } else { Some ( Box :: new ( self . macro_calls ) ) } ,
160156 self . diagnostics ,
161157 )
162158 }
163159
164- fn collect ( & mut self , item_tree : & ItemTree , tree_id : TreeId , assoc_items : & [ AssocItem ] ) {
165- let container = self . container ;
166- self . items . reserve ( assoc_items. len ( ) ) ;
167-
168- ' items: for & item in assoc_items {
169- let attrs = item_tree. attrs ( self . db , self . module_id . krate , ModItem :: from ( item) . into ( ) ) ;
170- if !attrs. is_cfg_enabled ( self . expander . cfg_options ( self . db ) ) {
171- self . diagnostics . push ( DefDiagnostic :: unconfigured_code (
172- self . module_id . local_id ,
173- tree_id,
174- ModItem :: from ( item) . into ( ) ,
175- attrs. cfg ( ) . unwrap ( ) ,
176- self . expander . cfg_options ( self . db ) . clone ( ) ,
177- ) ) ;
178- continue ;
179- }
180-
181- ' attrs: for attr in & * attrs {
182- let ast_id =
183- AstId :: new ( self . expander . current_file_id ( ) , item. ast_id ( item_tree) . upcast ( ) ) ;
184- let ast_id_with_path = AstIdWithPath { path : attr. path . clone ( ) , ast_id } ;
185-
186- match self . def_map . resolve_attr_macro (
187- & self . local_def_map ,
188- self . db ,
189- self . module_id . local_id ,
190- ast_id_with_path,
191- attr,
192- ) {
193- Ok ( ResolvedAttr :: Macro ( call_id) ) => {
194- let loc = self . db . lookup_intern_macro_call ( call_id) ;
195- if let MacroDefKind :: ProcMacro ( _, exp, _) = loc. def . kind {
196- // If there's no expander for the proc macro (e.g. the
197- // proc macro is ignored, or building the proc macro
198- // crate failed), skip expansion like we would if it was
199- // disabled. This is analogous to the handling in
200- // `DefCollector::collect_macros`.
201- if let Some ( err) = exp. as_expand_error ( self . module_id . krate ) {
202- self . diagnostics . push ( DefDiagnostic :: macro_error (
203- self . module_id . local_id ,
204- ast_id,
205- ( * attr. path ) . clone ( ) ,
206- err,
207- ) ) ;
208- continue ' attrs;
209- }
210- }
160+ fn collect_item ( & mut self , item_tree : & ItemTree , tree_id : TreeId , item : AssocItem ) {
161+ let attrs = item_tree. attrs ( self . db , self . module_id . krate , ModItem :: from ( item) . into ( ) ) ;
162+ if !attrs. is_cfg_enabled ( self . module_id . krate . cfg_options ( self . db ) ) {
163+ self . diagnostics . push ( DefDiagnostic :: unconfigured_code (
164+ self . module_id . local_id ,
165+ tree_id,
166+ ModItem :: from ( item) . into ( ) ,
167+ attrs. cfg ( ) . unwrap ( ) ,
168+ self . module_id . krate . cfg_options ( self . db ) . clone ( ) ,
169+ ) ) ;
170+ return ;
171+ }
211172
212- self . macro_calls . push ( ( ast_id, call_id) ) ;
213- let res =
214- self . expander . enter_expand_id :: < ast:: MacroItems > ( self . db , call_id) ;
215- self . collect_macro_items ( res) ;
216- continue ' items;
217- }
218- Ok ( _) => ( ) ,
219- Err ( _) => {
220- self . diagnostics . push ( DefDiagnostic :: unresolved_macro_call (
221- self . module_id . local_id ,
222- MacroCallKind :: Attr {
173+ ' attrs: for attr in & * attrs {
174+ let ast_id = AstId :: new ( tree_id. file_id ( ) , item. ast_id ( item_tree) . upcast ( ) ) ;
175+ let ast_id_with_path = AstIdWithPath { path : attr. path . clone ( ) , ast_id } ;
176+
177+ match self . def_map . resolve_attr_macro (
178+ & self . local_def_map ,
179+ self . db ,
180+ self . module_id . local_id ,
181+ ast_id_with_path,
182+ attr,
183+ ) {
184+ Ok ( ResolvedAttr :: Macro ( call_id) ) => {
185+ let loc = self . db . lookup_intern_macro_call ( call_id) ;
186+ if let MacroDefKind :: ProcMacro ( _, exp, _) = loc. def . kind {
187+ // If there's no expander for the proc macro (e.g. the
188+ // proc macro is ignored, or building the proc macro
189+ // crate failed), skip expansion like we would if it was
190+ // disabled. This is analogous to the handling in
191+ // `DefCollector::collect_macros`.
192+ if let Some ( err) = exp. as_expand_error ( self . module_id . krate ) {
193+ self . diagnostics . push ( DefDiagnostic :: macro_error (
194+ self . module_id . local_id ,
223195 ast_id,
224- attr_args : None ,
225- invoc_attr_index : attr . id ,
226- } ,
227- attr . path ( ) . clone ( ) ,
228- ) ) ;
196+ ( * attr . path ) . clone ( ) ,
197+ err ,
198+ ) ) ;
199+ continue ' attrs ;
200+ }
229201 }
202+
203+ self . macro_calls . push ( ( ast_id, call_id) ) ;
204+ self . collect_macro_items ( call_id) ;
205+ return ;
206+ }
207+ Ok ( _) => ( ) ,
208+ Err ( _) => {
209+ self . diagnostics . push ( DefDiagnostic :: unresolved_macro_call (
210+ self . module_id . local_id ,
211+ MacroCallKind :: Attr { ast_id, attr_args : None , invoc_attr_index : attr. id } ,
212+ attr. path ( ) . clone ( ) ,
213+ ) ) ;
230214 }
231215 }
232-
233- self . collect_item ( item_tree, tree_id, container, item) ;
234216 }
217+
218+ self . record_item ( item_tree, tree_id, item) ;
235219 }
236220
237- fn collect_item (
238- & mut self ,
239- item_tree : & ItemTree ,
240- tree_id : TreeId ,
241- container : ItemContainerId ,
242- item : AssocItem ,
243- ) {
221+ fn record_item ( & mut self , item_tree : & ItemTree , tree_id : TreeId , item : AssocItem ) {
244222 match item {
245223 AssocItem :: Function ( id) => {
246224 let item = & item_tree[ id] ;
247225 let def =
248- FunctionLoc { container, id : ItemTreeId :: new ( tree_id, id) } . intern ( self . db ) ;
226+ FunctionLoc { container : self . container , id : ItemTreeId :: new ( tree_id, id) }
227+ . intern ( self . db ) ;
249228 self . items . push ( ( item. name . clone ( ) , def. into ( ) ) ) ;
250229 }
251230 AssocItem :: TypeAlias ( id) => {
252231 let item = & item_tree[ id] ;
253232 let def =
254- TypeAliasLoc { container, id : ItemTreeId :: new ( tree_id, id) } . intern ( self . db ) ;
233+ TypeAliasLoc { container : self . container , id : ItemTreeId :: new ( tree_id, id) }
234+ . intern ( self . db ) ;
255235 self . items . push ( ( item. name . clone ( ) , def. into ( ) ) ) ;
256236 }
257237 AssocItem :: Const ( id) => {
258238 let item = & item_tree[ id] ;
259239 let Some ( name) = item. name . clone ( ) else { return } ;
260- let def = ConstLoc { container, id : ItemTreeId :: new ( tree_id, id) } . intern ( self . db ) ;
240+ let def = ConstLoc { container : self . container , id : ItemTreeId :: new ( tree_id, id) }
241+ . intern ( self . db ) ;
261242 self . items . push ( ( name, def. into ( ) ) ) ;
262243 }
263244 AssocItem :: MacroCall ( call) => {
264- let file_id = self . expander . current_file_id ( ) ;
265245 let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[ call] ;
266- let module = self . expander . module . local_id ;
267246
268247 let resolver = |path : & _ | {
269248 self . def_map
270249 . resolve_path (
271250 & self . local_def_map ,
272251 self . db ,
273- module ,
252+ self . module_id . local_id ,
274253 path,
275254 crate :: item_scope:: BuiltinShadowMode :: Other ,
276255 Some ( MacroSubNs :: Bang ) ,
@@ -281,24 +260,23 @@ impl<'a> AssocItemCollector<'a> {
281260 } ;
282261 match macro_call_as_call_id (
283262 self . db . upcast ( ) ,
284- & AstIdWithPath :: new ( file_id, ast_id, Clone :: clone ( path) ) ,
263+ & AstIdWithPath :: new ( tree_id . file_id ( ) , ast_id, Clone :: clone ( path) ) ,
285264 ctxt,
286265 expand_to,
287- self . expander . krate ( ) ,
266+ self . module_id . krate ( ) ,
288267 resolver,
289268 ) {
290269 Ok ( Some ( call_id) ) => {
291- let res =
292- self . expander . enter_expand_id :: < ast:: MacroItems > ( self . db , call_id) ;
293- self . macro_calls . push ( ( InFile :: new ( file_id, ast_id. upcast ( ) ) , call_id) ) ;
294- self . collect_macro_items ( res) ;
270+ self . macro_calls
271+ . push ( ( InFile :: new ( tree_id. file_id ( ) , ast_id. upcast ( ) ) , call_id) ) ;
272+ self . collect_macro_items ( call_id) ;
295273 }
296274 Ok ( None ) => ( ) ,
297275 Err ( _) => {
298276 self . diagnostics . push ( DefDiagnostic :: unresolved_macro_call (
299277 self . module_id . local_id ,
300278 MacroCallKind :: FnLike {
301- ast_id : InFile :: new ( file_id, ast_id) ,
279+ ast_id : InFile :: new ( tree_id . file_id ( ) , ast_id) ,
302280 expand_to,
303281 eager : None ,
304282 } ,
@@ -310,16 +288,19 @@ impl<'a> AssocItemCollector<'a> {
310288 }
311289 }
312290
313- fn collect_macro_items ( & mut self , res : ExpandResult < Option < ( Mark , Parse < ast:: MacroItems > ) > > ) {
314- let Some ( ( mark, _parse) ) = res. value else { return } ;
315-
316- let tree_id = item_tree:: TreeId :: new ( self . expander . current_file_id ( ) , None ) ;
317- let item_tree = tree_id. item_tree ( self . db ) ;
318- let iter: SmallVec < [ _ ; 2 ] > =
319- item_tree. top_level_items ( ) . iter ( ) . filter_map ( ModItem :: as_assoc_item) . collect ( ) ;
320-
321- self . collect ( & item_tree, tree_id, & iter) ;
291+ fn collect_macro_items ( & mut self , macro_call_id : MacroCallId ) {
292+ if self . depth > self . def_map . recursion_limit ( ) as usize {
293+ tracing:: warn!( "macro expansion is too deep" ) ;
294+ return ;
295+ }
296+ let file_id = macro_call_id. as_file ( ) ;
297+ let tree_id = TreeId :: new ( file_id, None ) ;
298+ let item_tree = self . db . file_item_tree ( file_id) ;
322299
323- self . expander . exit ( mark) ;
300+ self . depth += 1 ;
301+ for item in item_tree. top_level_items ( ) . iter ( ) . filter_map ( ModItem :: as_assoc_item) {
302+ self . collect_item ( & item_tree, tree_id, item) ;
303+ }
304+ self . depth -= 1 ;
324305 }
325306}
0 commit comments