]> git.lizzy.rs Git - rust.git/blob - src/librustc_resolve/def_collector.rs
Rollup merge of #70038 - DutchGhost:const-forget-tests, r=RalfJung
[rust.git] / src / librustc_resolve / def_collector.rs
1 use log::debug;
2 use rustc::hir::map::definitions::*;
3 use rustc_ast::ast::*;
4 use rustc_ast::token::{self, Token};
5 use rustc_ast::visit::{self, FnKind};
6 use rustc_expand::expand::AstFragment;
7 use rustc_hir::def_id::LocalDefId;
8 use rustc_span::hygiene::ExpnId;
9 use rustc_span::symbol::{kw, sym};
10 use rustc_span::Span;
11
12 crate fn collect_definitions(
13     definitions: &mut Definitions,
14     fragment: &AstFragment,
15     expansion: ExpnId,
16 ) {
17     let parent_def = definitions.invocation_parent(expansion);
18     fragment.visit_with(&mut DefCollector { definitions, parent_def, expansion });
19 }
20
21 /// Creates `DefId`s for nodes in the AST.
22 struct DefCollector<'a> {
23     definitions: &'a mut Definitions,
24     parent_def: LocalDefId,
25     expansion: ExpnId,
26 }
27
28 impl<'a> DefCollector<'a> {
29     fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId {
30         let parent_def = self.parent_def;
31         debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
32         self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span)
33     }
34
35     fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
36         let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def);
37         f(self);
38         self.parent_def = orig_parent_def;
39     }
40
41     fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
42         let index = |this: &Self| {
43             index.unwrap_or_else(|| {
44                 let node_id = NodeId::placeholder_from_expn_id(this.expansion);
45                 this.definitions.placeholder_field_index(node_id)
46             })
47         };
48
49         if field.is_placeholder {
50             self.definitions.set_placeholder_field_index(field.id, index(self));
51             self.visit_macro_invoc(field.id);
52         } else {
53             let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
54             let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span);
55             self.with_parent(def, |this| visit::walk_struct_field(this, field));
56         }
57     }
58
59     fn visit_macro_invoc(&mut self, id: NodeId) {
60         self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
61     }
62 }
63
64 impl<'a> visit::Visitor<'a> for DefCollector<'a> {
65     fn visit_item(&mut self, i: &'a Item) {
66         debug!("visit_item: {:?}", i);
67
68         // Pick the def data. This need not be unique, but the more
69         // information we encapsulate into, the better
70         let def_data = match &i.kind {
71             ItemKind::Impl { .. } => DefPathData::Impl,
72             ItemKind::Mod(..) if i.ident.name == kw::Invalid => {
73                 return visit::walk_item(self, i);
74             }
75             ItemKind::Mod(..)
76             | ItemKind::Trait(..)
77             | ItemKind::TraitAlias(..)
78             | ItemKind::Enum(..)
79             | ItemKind::Struct(..)
80             | ItemKind::Union(..)
81             | ItemKind::ExternCrate(..)
82             | ItemKind::ForeignMod(..)
83             | ItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name),
84             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => {
85                 DefPathData::ValueNs(i.ident.name)
86             }
87             ItemKind::MacroDef(..) => DefPathData::MacroNs(i.ident.name),
88             ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
89             ItemKind::GlobalAsm(..) => DefPathData::Misc,
90             ItemKind::Use(..) => {
91                 return visit::walk_item(self, i);
92             }
93         };
94         let def = self.create_def(i.id, def_data, i.span);
95
96         self.with_parent(def, |this| {
97             match i.kind {
98                 ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
99                     // If this is a unit or tuple-like struct, register the constructor.
100                     if let Some(ctor_hir_id) = struct_def.ctor_id() {
101                         this.create_def(ctor_hir_id, DefPathData::Ctor, i.span);
102                     }
103                 }
104                 _ => {}
105             }
106             visit::walk_item(this, i);
107         });
108     }
109
110     fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
111         if let FnKind::Fn(_, _, sig, _, body) = fn_kind {
112             if let Async::Yes { closure_id, return_impl_trait_id, .. } = sig.header.asyncness {
113                 self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span);
114
115                 // For async functions, we need to create their inner defs inside of a
116                 // closure to match their desugared representation. Besides that,
117                 // we must mirror everything that `visit::walk_fn` below does.
118                 self.visit_fn_header(&sig.header);
119                 visit::walk_fn_decl(self, &sig.decl);
120                 if let Some(body) = body {
121                     let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span);
122                     self.with_parent(closure_def, |this| this.visit_block(body));
123                 }
124                 return;
125             }
126         }
127
128         visit::walk_fn(self, fn_kind, span);
129     }
130
131     fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
132         self.create_def(id, DefPathData::Misc, use_tree.span);
133         visit::walk_use_tree(self, use_tree, id);
134     }
135
136     fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
137         if let ForeignItemKind::MacCall(_) = foreign_item.kind {
138             return self.visit_macro_invoc(foreign_item.id);
139         }
140
141         let def = self.create_def(
142             foreign_item.id,
143             DefPathData::ValueNs(foreign_item.ident.name),
144             foreign_item.span,
145         );
146
147         self.with_parent(def, |this| {
148             visit::walk_foreign_item(this, foreign_item);
149         });
150     }
151
152     fn visit_variant(&mut self, v: &'a Variant) {
153         if v.is_placeholder {
154             return self.visit_macro_invoc(v.id);
155         }
156         let def = self.create_def(v.id, DefPathData::TypeNs(v.ident.name), v.span);
157         self.with_parent(def, |this| {
158             if let Some(ctor_hir_id) = v.data.ctor_id() {
159                 this.create_def(ctor_hir_id, DefPathData::Ctor, v.span);
160             }
161             visit::walk_variant(this, v)
162         });
163     }
164
165     fn visit_variant_data(&mut self, data: &'a VariantData) {
166         // The assumption here is that non-`cfg` macro expansion cannot change field indices.
167         // It currently holds because only inert attributes are accepted on fields,
168         // and every such attribute expands into a single field after it's resolved.
169         for (index, field) in data.fields().iter().enumerate() {
170             self.collect_field(field, Some(index));
171         }
172     }
173
174     fn visit_generic_param(&mut self, param: &'a GenericParam) {
175         if param.is_placeholder {
176             self.visit_macro_invoc(param.id);
177             return;
178         }
179         let name = param.ident.name;
180         let def_path_data = match param.kind {
181             GenericParamKind::Lifetime { .. } => DefPathData::LifetimeNs(name),
182             GenericParamKind::Type { .. } => DefPathData::TypeNs(name),
183             GenericParamKind::Const { .. } => DefPathData::ValueNs(name),
184         };
185         self.create_def(param.id, def_path_data, param.ident.span);
186
187         visit::walk_generic_param(self, param);
188     }
189
190     fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
191         let def_data = match &i.kind {
192             AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name),
193             AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name),
194             AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
195         };
196
197         let def = self.create_def(i.id, def_data, i.span);
198         self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt));
199     }
200
201     fn visit_pat(&mut self, pat: &'a Pat) {
202         match pat.kind {
203             PatKind::MacCall(..) => return self.visit_macro_invoc(pat.id),
204             _ => visit::walk_pat(self, pat),
205         }
206     }
207
208     fn visit_anon_const(&mut self, constant: &'a AnonConst) {
209         let def = self.create_def(constant.id, DefPathData::AnonConst, constant.value.span);
210         self.with_parent(def, |this| visit::walk_anon_const(this, constant));
211     }
212
213     fn visit_expr(&mut self, expr: &'a Expr) {
214         let parent_def = match expr.kind {
215             ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
216             ExprKind::Closure(_, asyncness, ..) => {
217                 // Async closures desugar to closures inside of closures, so
218                 // we must create two defs.
219                 let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span);
220                 match asyncness {
221                     Async::Yes { closure_id, .. } => {
222                         self.create_def(closure_id, DefPathData::ClosureExpr, expr.span)
223                     }
224                     Async::No => closure_def,
225                 }
226             }
227             ExprKind::Async(_, async_id, _) => {
228                 self.create_def(async_id, DefPathData::ClosureExpr, expr.span)
229             }
230             _ => self.parent_def,
231         };
232
233         self.with_parent(parent_def, |this| visit::walk_expr(this, expr));
234     }
235
236     fn visit_ty(&mut self, ty: &'a Ty) {
237         match ty.kind {
238             TyKind::MacCall(..) => return self.visit_macro_invoc(ty.id),
239             TyKind::ImplTrait(node_id, _) => {
240                 self.create_def(node_id, DefPathData::ImplTrait, ty.span);
241             }
242             _ => {}
243         }
244         visit::walk_ty(self, ty);
245     }
246
247     fn visit_stmt(&mut self, stmt: &'a Stmt) {
248         match stmt.kind {
249             StmtKind::MacCall(..) => self.visit_macro_invoc(stmt.id),
250             _ => visit::walk_stmt(self, stmt),
251         }
252     }
253
254     fn visit_token(&mut self, t: Token) {
255         if let token::Interpolated(nt) = t.kind {
256             if let token::NtExpr(ref expr) = *nt {
257                 if let ExprKind::MacCall(..) = expr.kind {
258                     self.visit_macro_invoc(expr.id);
259                 }
260             }
261         }
262     }
263
264     fn visit_arm(&mut self, arm: &'a Arm) {
265         if arm.is_placeholder { self.visit_macro_invoc(arm.id) } else { visit::walk_arm(self, arm) }
266     }
267
268     fn visit_field(&mut self, f: &'a Field) {
269         if f.is_placeholder { self.visit_macro_invoc(f.id) } else { visit::walk_field(self, f) }
270     }
271
272     fn visit_field_pattern(&mut self, fp: &'a FieldPat) {
273         if fp.is_placeholder {
274             self.visit_macro_invoc(fp.id)
275         } else {
276             visit::walk_field_pattern(self, fp)
277         }
278     }
279
280     fn visit_param(&mut self, p: &'a Param) {
281         if p.is_placeholder { self.visit_macro_invoc(p.id) } else { visit::walk_param(self, p) }
282     }
283
284     // This method is called only when we are visiting an individual field
285     // after expanding an attribute on it.
286     fn visit_struct_field(&mut self, field: &'a StructField) {
287         self.collect_field(field, None);
288     }
289 }