1 use crate::{ImplTraitContext, Resolver}
;
2 use rustc_ast
::visit
::{self, FnKind}
;
3 use rustc_ast
::walk_list
;
5 use rustc_ast_lowering
::ResolverAstLowering
;
6 use rustc_expand
::expand
::AstFragment
;
7 use rustc_hir
::def_id
::LocalDefId
;
8 use rustc_hir
::definitions
::*;
9 use rustc_span
::hygiene
::LocalExpnId
;
10 use rustc_span
::symbol
::{kw, sym}
;
14 crate fn collect_definitions(
15 resolver
: &mut Resolver
<'_
>,
16 fragment
: &AstFragment
,
17 expansion
: LocalExpnId
,
19 let (parent_def
, impl_trait_context
) = resolver
.invocation_parents
[&expansion
];
20 fragment
.visit_with(&mut DefCollector { resolver, parent_def, expansion, impl_trait_context }
);
23 /// Creates `DefId`s for nodes in the AST.
24 struct DefCollector
<'a
, 'b
> {
25 resolver
: &'a
mut Resolver
<'b
>,
26 parent_def
: LocalDefId
,
27 impl_trait_context
: ImplTraitContext
,
28 expansion
: LocalExpnId
,
31 impl<'a
, 'b
> DefCollector
<'a
, 'b
> {
32 fn create_def(&mut self, node_id
: NodeId
, data
: DefPathData
, span
: Span
) -> LocalDefId
{
33 let parent_def
= self.parent_def
;
34 debug
!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id
, data
, parent_def
);
35 self.resolver
.create_def(parent_def
, node_id
, data
, self.expansion
.to_expn_id(), span
)
38 fn with_parent
<F
: FnOnce(&mut Self)>(&mut self, parent_def
: LocalDefId
, f
: F
) {
39 let orig_parent_def
= std
::mem
::replace(&mut self.parent_def
, parent_def
);
41 self.parent_def
= orig_parent_def
;
44 fn with_impl_trait
<F
: FnOnce(&mut Self)>(
46 impl_trait_context
: ImplTraitContext
,
49 let orig_itc
= std
::mem
::replace(&mut self.impl_trait_context
, impl_trait_context
);
51 self.impl_trait_context
= orig_itc
;
54 fn collect_field(&mut self, field
: &'a FieldDef
, index
: Option
<usize>) {
55 let index
= |this
: &Self| {
56 index
.unwrap_or_else(|| {
57 let node_id
= NodeId
::placeholder_from_expn_id(this
.expansion
);
58 this
.resolver
.placeholder_field_indices
[&node_id
]
62 if field
.is_placeholder
{
63 let old_index
= self.resolver
.placeholder_field_indices
.insert(field
.id
, index(self));
64 assert
!(old_index
.is_none(), "placeholder field index is reset for a node ID");
65 self.visit_macro_invoc(field
.id
);
67 let name
= field
.ident
.map_or_else(|| sym
::integer(index(self)), |ident
| ident
.name
);
68 let def
= self.create_def(field
.id
, DefPathData
::ValueNs(name
), field
.span
);
69 self.with_parent(def
, |this
| visit
::walk_field_def(this
, field
));
73 fn visit_macro_invoc(&mut self, id
: NodeId
) {
74 let id
= id
.placeholder_to_expn_id();
76 self.resolver
.invocation_parents
.insert(id
, (self.parent_def
, self.impl_trait_context
));
77 assert
!(old_parent
.is_none(), "parent `LocalDefId` is reset for an invocation");
81 impl<'a
, 'b
> visit
::Visitor
<'a
> for DefCollector
<'a
, 'b
> {
82 fn visit_item(&mut self, i
: &'a Item
) {
83 debug
!("visit_item: {:?}", i
);
85 // Pick the def data. This need not be unique, but the more
86 // information we encapsulate into, the better
87 let def_data
= match &i
.kind
{
88 ItemKind
::Impl { .. }
=> DefPathData
::Impl
,
89 ItemKind
::Mod(..) if i
.ident
.name
== kw
::Empty
=> {
90 // Fake crate root item from expand.
91 return visit
::walk_item(self, i
);
95 | ItemKind
::TraitAlias(..)
97 | ItemKind
::Struct(..)
99 | ItemKind
::ExternCrate(..)
100 | ItemKind
::ForeignMod(..)
101 | ItemKind
::TyAlias(..) => DefPathData
::TypeNs(i
.ident
.name
),
102 ItemKind
::Static(..) | ItemKind
::Const(..) | ItemKind
::Fn(..) => {
103 DefPathData
::ValueNs(i
.ident
.name
)
105 ItemKind
::MacroDef(..) => DefPathData
::MacroNs(i
.ident
.name
),
106 ItemKind
::MacCall(..) => {
107 visit
::walk_item(self, i
);
108 return self.visit_macro_invoc(i
.id
);
110 ItemKind
::GlobalAsm(..) => DefPathData
::Misc
,
111 ItemKind
::Use(..) => {
112 return visit
::walk_item(self, i
);
115 let def
= self.create_def(i
.id
, def_data
, i
.span
);
117 self.with_parent(def
, |this
| {
118 this
.with_impl_trait(ImplTraitContext
::Existential
, |this
| {
120 ItemKind
::Struct(ref struct_def
, _
) | ItemKind
::Union(ref struct_def
, _
) => {
121 // If this is a unit or tuple-like struct, register the constructor.
122 if let Some(ctor_hir_id
) = struct_def
.ctor_id() {
123 this
.create_def(ctor_hir_id
, DefPathData
::Ctor
, i
.span
);
128 visit
::walk_item(this
, i
);
133 fn visit_fn(&mut self, fn_kind
: FnKind
<'a
>, span
: Span
, _
: NodeId
) {
134 if let FnKind
::Fn(_
, _
, sig
, _
, body
) = fn_kind
{
135 if let Async
::Yes { closure_id, return_impl_trait_id, .. }
= sig
.header
.asyncness
{
136 let return_impl_trait_id
=
137 self.create_def(return_impl_trait_id
, DefPathData
::ImplTrait
, span
);
139 // For async functions, we need to create their inner defs inside of a
140 // closure to match their desugared representation. Besides that,
141 // we must mirror everything that `visit::walk_fn` below does.
142 self.visit_fn_header(&sig
.header
);
143 for param
in &sig
.decl
.inputs
{
144 self.visit_param(param
);
146 self.with_parent(return_impl_trait_id
, |this
| {
147 this
.visit_fn_ret_ty(&sig
.decl
.output
)
149 let closure_def
= self.create_def(closure_id
, DefPathData
::ClosureExpr
, span
);
150 self.with_parent(closure_def
, |this
| walk_list
!(this
, visit_block
, body
));
155 visit
::walk_fn(self, fn_kind
, span
);
158 fn visit_use_tree(&mut self, use_tree
: &'a UseTree
, id
: NodeId
, _nested
: bool
) {
159 self.create_def(id
, DefPathData
::Misc
, use_tree
.span
);
160 match use_tree
.kind
{
161 UseTreeKind
::Simple(_
, id1
, id2
) => {
162 self.create_def(id1
, DefPathData
::Misc
, use_tree
.prefix
.span
);
163 self.create_def(id2
, DefPathData
::Misc
, use_tree
.prefix
.span
);
165 UseTreeKind
::Glob
=> (),
166 UseTreeKind
::Nested(..) => {}
168 visit
::walk_use_tree(self, use_tree
, id
);
171 fn visit_foreign_item(&mut self, foreign_item
: &'a ForeignItem
) {
172 if let ForeignItemKind
::MacCall(_
) = foreign_item
.kind
{
173 return self.visit_macro_invoc(foreign_item
.id
);
176 let def
= self.create_def(
178 DefPathData
::ValueNs(foreign_item
.ident
.name
),
182 self.with_parent(def
, |this
| {
183 visit
::walk_foreign_item(this
, foreign_item
);
187 fn visit_variant(&mut self, v
: &'a Variant
) {
188 if v
.is_placeholder
{
189 return self.visit_macro_invoc(v
.id
);
191 let def
= self.create_def(v
.id
, DefPathData
::TypeNs(v
.ident
.name
), v
.span
);
192 self.with_parent(def
, |this
| {
193 if let Some(ctor_hir_id
) = v
.data
.ctor_id() {
194 this
.create_def(ctor_hir_id
, DefPathData
::Ctor
, v
.span
);
196 visit
::walk_variant(this
, v
)
200 fn visit_variant_data(&mut self, data
: &'a VariantData
) {
201 // The assumption here is that non-`cfg` macro expansion cannot change field indices.
202 // It currently holds because only inert attributes are accepted on fields,
203 // and every such attribute expands into a single field after it's resolved.
204 for (index
, field
) in data
.fields().iter().enumerate() {
205 self.collect_field(field
, Some(index
));
209 fn visit_generic_param(&mut self, param
: &'a GenericParam
) {
210 if param
.is_placeholder
{
211 self.visit_macro_invoc(param
.id
);
214 let name
= param
.ident
.name
;
215 let def_path_data
= match param
.kind
{
216 GenericParamKind
::Lifetime { .. }
=> DefPathData
::LifetimeNs(name
),
217 GenericParamKind
::Type { .. }
=> DefPathData
::TypeNs(name
),
218 GenericParamKind
::Const { .. }
=> DefPathData
::ValueNs(name
),
220 self.create_def(param
.id
, def_path_data
, param
.ident
.span
);
222 // impl-Trait can happen inside generic parameters, like
224 // fn foo<U: Iterator<Item = impl Clone>>() {}
227 // In that case, the impl-trait is lowered as an additional generic parameter.
228 self.with_impl_trait(ImplTraitContext
::Universal(self.parent_def
), |this
| {
229 visit
::walk_generic_param(this
, param
)
233 fn visit_assoc_item(&mut self, i
: &'a AssocItem
, ctxt
: visit
::AssocCtxt
) {
234 let def_data
= match &i
.kind
{
235 AssocItemKind
::Fn(..) | AssocItemKind
::Const(..) => DefPathData
::ValueNs(i
.ident
.name
),
236 AssocItemKind
::TyAlias(..) => DefPathData
::TypeNs(i
.ident
.name
),
237 AssocItemKind
::MacCall(..) => return self.visit_macro_invoc(i
.id
),
240 let def
= self.create_def(i
.id
, def_data
, i
.span
);
241 self.with_parent(def
, |this
| visit
::walk_assoc_item(this
, i
, ctxt
));
244 fn visit_pat(&mut self, pat
: &'a Pat
) {
246 PatKind
::MacCall(..) => self.visit_macro_invoc(pat
.id
),
247 _
=> visit
::walk_pat(self, pat
),
251 fn visit_anon_const(&mut self, constant
: &'a AnonConst
) {
252 let def
= self.create_def(constant
.id
, DefPathData
::AnonConst
, constant
.value
.span
);
253 self.with_parent(def
, |this
| visit
::walk_anon_const(this
, constant
));
256 fn visit_expr(&mut self, expr
: &'a Expr
) {
257 let parent_def
= match expr
.kind
{
258 ExprKind
::MacCall(..) => return self.visit_macro_invoc(expr
.id
),
259 ExprKind
::Closure(_
, asyncness
, ..) => {
260 // Async closures desugar to closures inside of closures, so
261 // we must create two defs.
262 let closure_def
= self.create_def(expr
.id
, DefPathData
::ClosureExpr
, expr
.span
);
264 Async
::Yes { closure_id, .. }
=> {
265 self.create_def(closure_id
, DefPathData
::ClosureExpr
, expr
.span
)
267 Async
::No
=> closure_def
,
270 ExprKind
::Async(_
, async_id
, _
) => {
271 self.create_def(async_id
, DefPathData
::ClosureExpr
, expr
.span
)
273 _
=> self.parent_def
,
276 self.with_parent(parent_def
, |this
| visit
::walk_expr(this
, expr
));
279 fn visit_ty(&mut self, ty
: &'a Ty
) {
281 TyKind
::MacCall(..) => self.visit_macro_invoc(ty
.id
),
282 TyKind
::ImplTrait(node_id
, _
) => {
283 let parent_def
= match self.impl_trait_context
{
284 ImplTraitContext
::Universal(item_def
) => self.resolver
.create_def(
287 DefPathData
::ImplTrait
,
288 self.expansion
.to_expn_id(),
291 ImplTraitContext
::Existential
=> {
292 self.create_def(node_id
, DefPathData
::ImplTrait
, ty
.span
)
295 self.with_parent(parent_def
, |this
| visit
::walk_ty(this
, ty
))
297 _
=> visit
::walk_ty(self, ty
),
301 fn visit_stmt(&mut self, stmt
: &'a Stmt
) {
303 StmtKind
::MacCall(..) => self.visit_macro_invoc(stmt
.id
),
304 _
=> visit
::walk_stmt(self, stmt
),
308 fn visit_arm(&mut self, arm
: &'a Arm
) {
309 if arm
.is_placeholder { self.visit_macro_invoc(arm.id) }
else { visit::walk_arm(self, arm) }
312 fn visit_expr_field(&mut self, f
: &'a ExprField
) {
313 if f
.is_placeholder
{
314 self.visit_macro_invoc(f
.id
)
316 visit
::walk_expr_field(self, f
)
320 fn visit_pat_field(&mut self, fp
: &'a PatField
) {
321 if fp
.is_placeholder
{
322 self.visit_macro_invoc(fp
.id
)
324 visit
::walk_pat_field(self, fp
)
328 fn visit_param(&mut self, p
: &'a Param
) {
329 if p
.is_placeholder
{
330 self.visit_macro_invoc(p
.id
)
332 self.with_impl_trait(ImplTraitContext
::Universal(self.parent_def
), |this
| {
333 visit
::walk_param(this
, p
)
338 // This method is called only when we are visiting an individual field
339 // after expanding an attribute on it.
340 fn visit_field_def(&mut self, field
: &'a FieldDef
) {
341 self.collect_field(field
, None
);