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
::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(
39 self.expansion
.to_expn_id(),
40 span
.with_parent(None
),
44 fn with_parent
<F
: FnOnce(&mut Self)>(&mut self, parent_def
: LocalDefId
, f
: F
) {
45 let orig_parent_def
= std
::mem
::replace(&mut self.parent_def
, parent_def
);
47 self.parent_def
= orig_parent_def
;
50 fn with_impl_trait
<F
: FnOnce(&mut Self)>(
52 impl_trait_context
: ImplTraitContext
,
55 let orig_itc
= std
::mem
::replace(&mut self.impl_trait_context
, impl_trait_context
);
57 self.impl_trait_context
= orig_itc
;
60 fn collect_field(&mut self, field
: &'a FieldDef
, index
: Option
<usize>) {
61 let index
= |this
: &Self| {
62 index
.unwrap_or_else(|| {
63 let node_id
= NodeId
::placeholder_from_expn_id(this
.expansion
);
64 this
.resolver
.placeholder_field_indices
[&node_id
]
68 if field
.is_placeholder
{
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");
71 self.visit_macro_invoc(field
.id
);
73 let name
= field
.ident
.map_or_else(|| sym
::integer(index(self)), |ident
| ident
.name
);
74 let def
= self.create_def(field
.id
, DefPathData
::ValueNs(name
), field
.span
);
75 self.with_parent(def
, |this
| visit
::walk_field_def(this
, field
));
79 fn visit_macro_invoc(&mut self, id
: NodeId
) {
80 let id
= id
.placeholder_to_expn_id();
82 self.resolver
.invocation_parents
.insert(id
, (self.parent_def
, self.impl_trait_context
));
83 assert
!(old_parent
.is_none(), "parent `LocalDefId` is reset for an invocation");
87 impl<'a
, 'b
> visit
::Visitor
<'a
> for DefCollector
<'a
, 'b
> {
88 fn visit_item(&mut self, i
: &'a Item
) {
89 debug
!("visit_item: {:?}", i
);
91 // Pick the def data. This need not be unique, but the more
92 // information we encapsulate into, the better
93 let def_data
= match &i
.kind
{
94 ItemKind
::Impl { .. }
=> DefPathData
::Impl
,
95 ItemKind
::ForeignMod(..) => DefPathData
::ForeignMod
,
98 | ItemKind
::TraitAlias(..)
100 | ItemKind
::Struct(..)
101 | ItemKind
::Union(..)
102 | ItemKind
::ExternCrate(..)
103 | ItemKind
::TyAlias(..) => DefPathData
::TypeNs(i
.ident
.name
),
104 ItemKind
::Static(..) | ItemKind
::Const(..) | ItemKind
::Fn(..) => {
105 DefPathData
::ValueNs(i
.ident
.name
)
107 ItemKind
::MacroDef(..) => DefPathData
::MacroNs(i
.ident
.name
),
108 ItemKind
::MacCall(..) => {
109 visit
::walk_item(self, i
);
110 return self.visit_macro_invoc(i
.id
);
112 ItemKind
::GlobalAsm(..) => DefPathData
::Misc
,
113 ItemKind
::Use(..) => {
114 return visit
::walk_item(self, i
);
117 let def
= self.create_def(i
.id
, def_data
, i
.span
);
119 self.with_parent(def
, |this
| {
120 this
.with_impl_trait(ImplTraitContext
::Existential
, |this
| {
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
);
130 visit
::walk_item(this
, i
);
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
{
138 let return_impl_trait_id
=
139 self.create_def(return_impl_trait_id
, DefPathData
::ImplTrait
, span
);
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
);
145 for param
in &sig
.decl
.inputs
{
146 self.visit_param(param
);
148 self.with_parent(return_impl_trait_id
, |this
| {
149 this
.visit_fn_ret_ty(&sig
.decl
.output
)
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
));
157 visit
::walk_fn(self, fn_kind
, span
);
160 fn visit_use_tree(&mut self, use_tree
: &'a UseTree
, id
: NodeId
, _nested
: bool
) {
161 self.create_def(id
, DefPathData
::Misc
, use_tree
.span
);
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
);
167 UseTreeKind
::Glob
=> (),
168 UseTreeKind
::Nested(..) => {}
170 visit
::walk_use_tree(self, use_tree
, id
);
173 fn visit_foreign_item(&mut self, foreign_item
: &'a ForeignItem
) {
174 if let ForeignItemKind
::MacCall(_
) = foreign_item
.kind
{
175 return self.visit_macro_invoc(foreign_item
.id
);
178 let def
= self.create_def(
180 DefPathData
::ValueNs(foreign_item
.ident
.name
),
184 self.with_parent(def
, |this
| {
185 visit
::walk_foreign_item(this
, foreign_item
);
189 fn visit_variant(&mut self, v
: &'a Variant
) {
190 if v
.is_placeholder
{
191 return self.visit_macro_invoc(v
.id
);
193 let def
= self.create_def(v
.id
, DefPathData
::TypeNs(v
.ident
.name
), v
.span
);
194 self.with_parent(def
, |this
| {
195 if let Some(ctor_hir_id
) = v
.data
.ctor_id() {
196 this
.create_def(ctor_hir_id
, DefPathData
::Ctor
, v
.span
);
198 visit
::walk_variant(this
, v
)
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.
206 for (index
, field
) in data
.fields().iter().enumerate() {
207 self.collect_field(field
, Some(index
));
211 fn visit_generic_param(&mut self, param
: &'a GenericParam
) {
212 if param
.is_placeholder
{
213 self.visit_macro_invoc(param
.id
);
216 let name
= param
.ident
.name
;
217 let def_path_data
= match param
.kind
{
218 GenericParamKind
::Lifetime { .. }
=> DefPathData
::LifetimeNs(name
),
219 GenericParamKind
::Type { .. }
=> DefPathData
::TypeNs(name
),
220 GenericParamKind
::Const { .. }
=> DefPathData
::ValueNs(name
),
222 self.create_def(param
.id
, def_path_data
, param
.ident
.span
);
224 // impl-Trait can happen inside generic parameters, like
226 // fn foo<U: Iterator<Item = impl Clone>>() {}
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
)
235 fn visit_assoc_item(&mut self, i
: &'a AssocItem
, ctxt
: visit
::AssocCtxt
) {
236 let def_data
= match &i
.kind
{
237 AssocItemKind
::Fn(..) | AssocItemKind
::Const(..) => DefPathData
::ValueNs(i
.ident
.name
),
238 AssocItemKind
::TyAlias(..) => DefPathData
::TypeNs(i
.ident
.name
),
239 AssocItemKind
::MacCall(..) => return self.visit_macro_invoc(i
.id
),
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
));
246 fn visit_pat(&mut self, pat
: &'a Pat
) {
248 PatKind
::MacCall(..) => self.visit_macro_invoc(pat
.id
),
249 _
=> visit
::walk_pat(self, pat
),
253 fn visit_anon_const(&mut self, constant
: &'a AnonConst
) {
254 let def
= self.create_def(constant
.id
, DefPathData
::AnonConst
, constant
.value
.span
);
255 self.with_parent(def
, |this
| visit
::walk_anon_const(this
, constant
));
258 fn visit_expr(&mut self, expr
: &'a Expr
) {
259 let parent_def
= match expr
.kind
{
260 ExprKind
::MacCall(..) => return self.visit_macro_invoc(expr
.id
),
261 ExprKind
::Closure(_
, asyncness
, ..) => {
262 // Async closures desugar to closures inside of closures, so
263 // we must create two defs.
264 let closure_def
= self.create_def(expr
.id
, DefPathData
::ClosureExpr
, expr
.span
);
266 Async
::Yes { closure_id, .. }
=> {
267 self.create_def(closure_id
, DefPathData
::ClosureExpr
, expr
.span
)
269 Async
::No
=> closure_def
,
272 ExprKind
::Async(_
, async_id
, _
) => {
273 self.create_def(async_id
, DefPathData
::ClosureExpr
, expr
.span
)
275 _
=> self.parent_def
,
278 self.with_parent(parent_def
, |this
| visit
::walk_expr(this
, expr
));
281 fn visit_ty(&mut self, ty
: &'a Ty
) {
283 TyKind
::MacCall(..) => self.visit_macro_invoc(ty
.id
),
284 TyKind
::ImplTrait(node_id
, _
) => {
285 let parent_def
= match self.impl_trait_context
{
286 ImplTraitContext
::Universal(item_def
) => self.resolver
.create_def(
289 DefPathData
::ImplTrait
,
290 self.expansion
.to_expn_id(),
293 ImplTraitContext
::Existential
=> {
294 self.create_def(node_id
, DefPathData
::ImplTrait
, ty
.span
)
297 self.with_parent(parent_def
, |this
| visit
::walk_ty(this
, ty
))
299 _
=> visit
::walk_ty(self, ty
),
303 fn visit_stmt(&mut self, stmt
: &'a Stmt
) {
305 StmtKind
::MacCall(..) => self.visit_macro_invoc(stmt
.id
),
306 _
=> visit
::walk_stmt(self, stmt
),
310 fn visit_arm(&mut self, arm
: &'a Arm
) {
311 if arm
.is_placeholder { self.visit_macro_invoc(arm.id) }
else { visit::walk_arm(self, arm) }
314 fn visit_expr_field(&mut self, f
: &'a ExprField
) {
315 if f
.is_placeholder
{
316 self.visit_macro_invoc(f
.id
)
318 visit
::walk_expr_field(self, f
)
322 fn visit_pat_field(&mut self, fp
: &'a PatField
) {
323 if fp
.is_placeholder
{
324 self.visit_macro_invoc(fp
.id
)
326 visit
::walk_pat_field(self, fp
)
330 fn visit_param(&mut self, p
: &'a Param
) {
331 if p
.is_placeholder
{
332 self.visit_macro_invoc(p
.id
)
334 self.with_impl_trait(ImplTraitContext
::Universal(self.parent_def
), |this
| {
335 visit
::walk_param(this
, p
)
340 // This method is called only when we are visiting an individual field
341 // after expanding an attribute on it.
342 fn visit_field_def(&mut self, field
: &'a FieldDef
) {
343 self.collect_field(field
, None
);
346 fn visit_crate(&mut self, krate
: &'a Crate
) {
347 if krate
.is_placeholder
{
348 self.visit_macro_invoc(krate
.id
)
350 visit
::walk_crate(self, krate
)