]>
Commit | Line | Data |
---|---|---|
6a06907d | 1 | use crate::{ImplTraitContext, Resolver}; |
ba9703b0 XL |
2 | use rustc_ast::visit::{self, FnKind}; |
3 | use rustc_ast::walk_list; | |
3dfed10e | 4 | use rustc_ast::*; |
f035d41b | 5 | use rustc_ast_lowering::ResolverAstLowering; |
dfeec247 | 6 | use rustc_expand::expand::AstFragment; |
ba9703b0 XL |
7 | use rustc_hir::def_id::LocalDefId; |
8 | use rustc_hir::definitions::*; | |
136023e0 | 9 | use rustc_span::hygiene::LocalExpnId; |
a2a8927a | 10 | use rustc_span::symbol::sym; |
dfeec247 | 11 | use rustc_span::Span; |
3dfed10e | 12 | use tracing::debug; |
a7813a04 | 13 | |
60c5eb7d | 14 | crate fn collect_definitions( |
f035d41b | 15 | resolver: &mut Resolver<'_>, |
60c5eb7d | 16 | fragment: &AstFragment, |
136023e0 | 17 | expansion: LocalExpnId, |
60c5eb7d | 18 | ) { |
6a06907d XL |
19 | let (parent_def, impl_trait_context) = resolver.invocation_parents[&expansion]; |
20 | fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion, impl_trait_context }); | |
60c5eb7d XL |
21 | } |
22 | ||
9fa01778 | 23 | /// Creates `DefId`s for nodes in the AST. |
f035d41b XL |
24 | struct DefCollector<'a, 'b> { |
25 | resolver: &'a mut Resolver<'b>, | |
ba9703b0 | 26 | parent_def: LocalDefId, |
6a06907d | 27 | impl_trait_context: ImplTraitContext, |
136023e0 | 28 | expansion: LocalExpnId, |
c30ab7b3 SL |
29 | } |
30 | ||
f035d41b | 31 | impl<'a, 'b> DefCollector<'a, 'b> { |
ba9703b0 | 32 | fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId { |
416331ca | 33 | let parent_def = self.parent_def; |
a7813a04 | 34 | debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); |
c295e0f8 XL |
35 | self.resolver.create_def( |
36 | parent_def, | |
37 | node_id, | |
38 | data, | |
39 | self.expansion.to_expn_id(), | |
40 | span.with_parent(None), | |
41 | ) | |
a7813a04 XL |
42 | } |
43 | ||
ba9703b0 | 44 | fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) { |
416331ca | 45 | let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def); |
a7813a04 | 46 | f(self); |
416331ca | 47 | self.parent_def = orig_parent_def; |
a7813a04 XL |
48 | } |
49 | ||
6a06907d XL |
50 | fn with_impl_trait<F: FnOnce(&mut Self)>( |
51 | &mut self, | |
52 | impl_trait_context: ImplTraitContext, | |
53 | f: F, | |
54 | ) { | |
55 | let orig_itc = std::mem::replace(&mut self.impl_trait_context, impl_trait_context); | |
56 | f(self); | |
57 | self.impl_trait_context = orig_itc; | |
58 | } | |
59 | ||
60 | fn collect_field(&mut self, field: &'a FieldDef, index: Option<usize>) { | |
dfeec247 XL |
61 | let index = |this: &Self| { |
62 | index.unwrap_or_else(|| { | |
63 | let node_id = NodeId::placeholder_from_expn_id(this.expansion); | |
f035d41b | 64 | this.resolver.placeholder_field_indices[&node_id] |
dfeec247 XL |
65 | }) |
66 | }; | |
e74abb32 | 67 | |
e1599b0c | 68 | if field.is_placeholder { |
f035d41b XL |
69 | let old_index = self.resolver.placeholder_field_indices.insert(field.id, index(self)); |
70 | assert!(old_index.is_none(), "placeholder field index is reset for a node ID"); | |
e1599b0c XL |
71 | self.visit_macro_invoc(field.id); |
72 | } else { | |
e74abb32 | 73 | let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name); |
e1599b0c | 74 | let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span); |
6a06907d | 75 | self.with_parent(def, |this| visit::walk_field_def(this, field)); |
e1599b0c XL |
76 | } |
77 | } | |
78 | ||
e74abb32 | 79 | fn visit_macro_invoc(&mut self, id: NodeId) { |
6a06907d | 80 | let id = id.placeholder_to_expn_id(); |
f035d41b | 81 | let old_parent = |
6a06907d | 82 | self.resolver.invocation_parents.insert(id, (self.parent_def, self.impl_trait_context)); |
f035d41b | 83 | assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation"); |
c30ab7b3 | 84 | } |
a7813a04 XL |
85 | } |
86 | ||
f035d41b | 87 | impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { |
476ff2be | 88 | fn visit_item(&mut self, i: &'a Item) { |
a7813a04 XL |
89 | debug!("visit_item: {:?}", i); |
90 | ||
91 | // Pick the def data. This need not be unique, but the more | |
94b46f34 | 92 | // information we encapsulate into, the better |
60c5eb7d | 93 | let def_data = match &i.kind { |
dfeec247 | 94 | ItemKind::Impl { .. } => DefPathData::Impl, |
a2a8927a | 95 | ItemKind::ForeignMod(..) => DefPathData::ForeignMod, |
dfeec247 XL |
96 | ItemKind::Mod(..) |
97 | | ItemKind::Trait(..) | |
98 | | ItemKind::TraitAlias(..) | |
99 | | ItemKind::Enum(..) | |
100 | | ItemKind::Struct(..) | |
101 | | ItemKind::Union(..) | |
102 | | ItemKind::ExternCrate(..) | |
dfeec247 | 103 | | ItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), |
dfeec247 XL |
104 | ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => { |
105 | DefPathData::ValueNs(i.ident.name) | |
8faf50e0 | 106 | } |
e74abb32 | 107 | ItemKind::MacroDef(..) => DefPathData::MacroNs(i.ident.name), |
5869c6ff XL |
108 | ItemKind::MacCall(..) => { |
109 | visit::walk_item(self, i); | |
110 | return self.visit_macro_invoc(i.id); | |
111 | } | |
cc61c64b | 112 | ItemKind::GlobalAsm(..) => DefPathData::Misc, |
ff7c6d11 XL |
113 | ItemKind::Use(..) => { |
114 | return visit::walk_item(self, i); | |
476ff2be | 115 | } |
a7813a04 | 116 | }; |
48663c56 | 117 | let def = self.create_def(i.id, def_data, i.span); |
a7813a04 XL |
118 | |
119 | self.with_parent(def, |this| { | |
6a06907d XL |
120 | this.with_impl_trait(ImplTraitContext::Existential, |this| { |
121 | match i.kind { | |
122 | ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { | |
123 | // If this is a unit or tuple-like struct, register the constructor. | |
124 | if let Some(ctor_hir_id) = struct_def.ctor_id() { | |
125 | this.create_def(ctor_hir_id, DefPathData::Ctor, i.span); | |
126 | } | |
a7813a04 | 127 | } |
6a06907d | 128 | _ => {} |
a7813a04 | 129 | } |
6a06907d XL |
130 | visit::walk_item(this, i); |
131 | }) | |
a7813a04 XL |
132 | }); |
133 | } | |
134 | ||
ba9703b0 XL |
135 | fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { |
136 | if let FnKind::Fn(_, _, sig, _, body) = fn_kind { | |
137 | if let Async::Yes { closure_id, return_impl_trait_id, .. } = sig.header.asyncness { | |
6a06907d XL |
138 | let return_impl_trait_id = |
139 | self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span); | |
ba9703b0 XL |
140 | |
141 | // For async functions, we need to create their inner defs inside of a | |
142 | // closure to match their desugared representation. Besides that, | |
143 | // we must mirror everything that `visit::walk_fn` below does. | |
144 | self.visit_fn_header(&sig.header); | |
6a06907d XL |
145 | for param in &sig.decl.inputs { |
146 | self.visit_param(param); | |
147 | } | |
148 | self.with_parent(return_impl_trait_id, |this| { | |
149 | this.visit_fn_ret_ty(&sig.decl.output) | |
150 | }); | |
ba9703b0 XL |
151 | let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span); |
152 | self.with_parent(closure_def, |this| walk_list!(this, visit_block, body)); | |
153 | return; | |
154 | } | |
155 | } | |
156 | ||
157 | visit::walk_fn(self, fn_kind, span); | |
158 | } | |
159 | ||
ff7c6d11 | 160 | fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { |
48663c56 | 161 | self.create_def(id, DefPathData::Misc, use_tree.span); |
6a06907d XL |
162 | match use_tree.kind { |
163 | UseTreeKind::Simple(_, id1, id2) => { | |
164 | self.create_def(id1, DefPathData::Misc, use_tree.prefix.span); | |
165 | self.create_def(id2, DefPathData::Misc, use_tree.prefix.span); | |
166 | } | |
167 | UseTreeKind::Glob => (), | |
168 | UseTreeKind::Nested(..) => {} | |
169 | } | |
ff7c6d11 XL |
170 | visit::walk_use_tree(self, use_tree, id); |
171 | } | |
172 | ||
476ff2be | 173 | fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { |
ba9703b0 | 174 | if let ForeignItemKind::MacCall(_) = foreign_item.kind { |
94b46f34 | 175 | return self.visit_macro_invoc(foreign_item.id); |
83c7162d XL |
176 | } |
177 | ||
dfeec247 XL |
178 | let def = self.create_def( |
179 | foreign_item.id, | |
180 | DefPathData::ValueNs(foreign_item.ident.name), | |
181 | foreign_item.span, | |
182 | ); | |
a7813a04 XL |
183 | |
184 | self.with_parent(def, |this| { | |
185 | visit::walk_foreign_item(this, foreign_item); | |
186 | }); | |
187 | } | |
188 | ||
e1599b0c XL |
189 | fn visit_variant(&mut self, v: &'a Variant) { |
190 | if v.is_placeholder { | |
191 | return self.visit_macro_invoc(v.id); | |
192 | } | |
dfeec247 | 193 | let def = self.create_def(v.id, DefPathData::TypeNs(v.ident.name), v.span); |
532ac7d7 | 194 | self.with_parent(def, |this| { |
e1599b0c | 195 | if let Some(ctor_hir_id) = v.data.ctor_id() { |
48663c56 | 196 | this.create_def(ctor_hir_id, DefPathData::Ctor, v.span); |
532ac7d7 | 197 | } |
e1599b0c | 198 | visit::walk_variant(this, v) |
532ac7d7 | 199 | }); |
94b46f34 XL |
200 | } |
201 | ||
e1599b0c XL |
202 | fn visit_variant_data(&mut self, data: &'a VariantData) { |
203 | // The assumption here is that non-`cfg` macro expansion cannot change field indices. | |
204 | // It currently holds because only inert attributes are accepted on fields, | |
205 | // and every such attribute expands into a single field after it's resolved. | |
94b46f34 | 206 | for (index, field) in data.fields().iter().enumerate() { |
e1599b0c | 207 | self.collect_field(field, Some(index)); |
94b46f34 XL |
208 | } |
209 | } | |
210 | ||
ff7c6d11 | 211 | fn visit_generic_param(&mut self, param: &'a GenericParam) { |
e1599b0c XL |
212 | if param.is_placeholder { |
213 | self.visit_macro_invoc(param.id); | |
214 | return; | |
215 | } | |
e74abb32 | 216 | let name = param.ident.name; |
8faf50e0 | 217 | let def_path_data = match param.kind { |
48663c56 XL |
218 | GenericParamKind::Lifetime { .. } => DefPathData::LifetimeNs(name), |
219 | GenericParamKind::Type { .. } => DefPathData::TypeNs(name), | |
220 | GenericParamKind::Const { .. } => DefPathData::ValueNs(name), | |
8faf50e0 | 221 | }; |
48663c56 | 222 | self.create_def(param.id, def_path_data, param.ident.span); |
a7813a04 | 223 | |
6a06907d XL |
224 | // impl-Trait can happen inside generic parameters, like |
225 | // ``` | |
226 | // fn foo<U: Iterator<Item = impl Clone>>() {} | |
227 | // ``` | |
228 | // | |
229 | // In that case, the impl-trait is lowered as an additional generic parameter. | |
230 | self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| { | |
231 | visit::walk_generic_param(this, param) | |
232 | }); | |
a7813a04 XL |
233 | } |
234 | ||
74b04a01 XL |
235 | fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { |
236 | let def_data = match &i.kind { | |
74b04a01 XL |
237 | AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name), |
238 | AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), | |
ba9703b0 | 239 | AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), |
a7813a04 XL |
240 | }; |
241 | ||
74b04a01 XL |
242 | let def = self.create_def(i.id, def_data, i.span); |
243 | self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); | |
a7813a04 XL |
244 | } |
245 | ||
476ff2be | 246 | fn visit_pat(&mut self, pat: &'a Pat) { |
e74abb32 | 247 | match pat.kind { |
ba9703b0 | 248 | PatKind::MacCall(..) => self.visit_macro_invoc(pat.id), |
ea8adc8c | 249 | _ => visit::walk_pat(self, pat), |
a7813a04 | 250 | } |
a7813a04 XL |
251 | } |
252 | ||
94b46f34 | 253 | fn visit_anon_const(&mut self, constant: &'a AnonConst) { |
dfeec247 | 254 | let def = self.create_def(constant.id, DefPathData::AnonConst, constant.value.span); |
94b46f34 XL |
255 | self.with_parent(def, |this| visit::walk_anon_const(this, constant)); |
256 | } | |
257 | ||
476ff2be | 258 | fn visit_expr(&mut self, expr: &'a Expr) { |
e74abb32 | 259 | let parent_def = match expr.kind { |
ba9703b0 | 260 | ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), |
dc9dc135 | 261 | ExprKind::Closure(_, asyncness, ..) => { |
8faf50e0 XL |
262 | // Async closures desugar to closures inside of closures, so |
263 | // we must create two defs. | |
416331ca XL |
264 | let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span); |
265 | match asyncness { | |
74b04a01 | 266 | Async::Yes { closure_id, .. } => { |
dfeec247 XL |
267 | self.create_def(closure_id, DefPathData::ClosureExpr, expr.span) |
268 | } | |
74b04a01 | 269 | Async::No => closure_def, |
8faf50e0 XL |
270 | } |
271 | } | |
dfeec247 XL |
272 | ExprKind::Async(_, async_id, _) => { |
273 | self.create_def(async_id, DefPathData::ClosureExpr, expr.span) | |
274 | } | |
416331ca | 275 | _ => self.parent_def, |
8faf50e0 | 276 | }; |
a7813a04 | 277 | |
416331ca | 278 | self.with_parent(parent_def, |this| visit::walk_expr(this, expr)); |
a7813a04 XL |
279 | } |
280 | ||
476ff2be | 281 | fn visit_ty(&mut self, ty: &'a Ty) { |
e74abb32 | 282 | match ty.kind { |
29967ef6 | 283 | TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), |
8faf50e0 | 284 | TyKind::ImplTrait(node_id, _) => { |
6a06907d XL |
285 | let parent_def = match self.impl_trait_context { |
286 | ImplTraitContext::Universal(item_def) => self.resolver.create_def( | |
287 | item_def, | |
288 | node_id, | |
289 | DefPathData::ImplTrait, | |
136023e0 | 290 | self.expansion.to_expn_id(), |
6a06907d XL |
291 | ty.span, |
292 | ), | |
293 | ImplTraitContext::Existential => { | |
294 | self.create_def(node_id, DefPathData::ImplTrait, ty.span) | |
295 | } | |
296 | }; | |
297 | self.with_parent(parent_def, |this| visit::walk_ty(this, ty)) | |
8faf50e0 | 298 | } |
29967ef6 | 299 | _ => visit::walk_ty(self, ty), |
5bcae85e | 300 | } |
a7813a04 XL |
301 | } |
302 | ||
476ff2be | 303 | fn visit_stmt(&mut self, stmt: &'a Stmt) { |
e74abb32 | 304 | match stmt.kind { |
ba9703b0 | 305 | StmtKind::MacCall(..) => self.visit_macro_invoc(stmt.id), |
c30ab7b3 SL |
306 | _ => visit::walk_stmt(self, stmt), |
307 | } | |
308 | } | |
abe05a73 | 309 | |
e1599b0c | 310 | fn visit_arm(&mut self, arm: &'a Arm) { |
dfeec247 | 311 | if arm.is_placeholder { self.visit_macro_invoc(arm.id) } else { visit::walk_arm(self, arm) } |
e1599b0c XL |
312 | } |
313 | ||
6a06907d XL |
314 | fn visit_expr_field(&mut self, f: &'a ExprField) { |
315 | if f.is_placeholder { | |
316 | self.visit_macro_invoc(f.id) | |
317 | } else { | |
318 | visit::walk_expr_field(self, f) | |
319 | } | |
e1599b0c XL |
320 | } |
321 | ||
6a06907d | 322 | fn visit_pat_field(&mut self, fp: &'a PatField) { |
e1599b0c XL |
323 | if fp.is_placeholder { |
324 | self.visit_macro_invoc(fp.id) | |
325 | } else { | |
6a06907d | 326 | visit::walk_pat_field(self, fp) |
e1599b0c XL |
327 | } |
328 | } | |
329 | ||
330 | fn visit_param(&mut self, p: &'a Param) { | |
6a06907d XL |
331 | if p.is_placeholder { |
332 | self.visit_macro_invoc(p.id) | |
333 | } else { | |
334 | self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| { | |
335 | visit::walk_param(this, p) | |
336 | }) | |
337 | } | |
e1599b0c XL |
338 | } |
339 | ||
340 | // This method is called only when we are visiting an individual field | |
341 | // after expanding an attribute on it. | |
6a06907d | 342 | fn visit_field_def(&mut self, field: &'a FieldDef) { |
e1599b0c XL |
343 | self.collect_field(field, None); |
344 | } | |
a2a8927a XL |
345 | |
346 | fn visit_crate(&mut self, krate: &'a Crate) { | |
347 | if krate.is_placeholder { | |
348 | self.visit_macro_invoc(krate.id) | |
349 | } else { | |
350 | visit::walk_crate(self, krate) | |
351 | } | |
352 | } | |
a7813a04 | 353 | } |