2021-02-13 20:41:02 +01:00
|
|
|
use std::mem;
|
2024-07-29 08:13:50 +10:00
|
|
|
|
2023-11-10 10:11:24 +08:00
|
|
|
use rustc_ast::visit::FnKind;
|
2020-04-27 23:26:11 +05:30
|
|
|
use rustc_ast::*;
|
2024-08-24 01:44:52 +00:00
|
|
|
use rustc_ast_pretty::pprust;
|
2025-02-09 22:49:33 +01:00
|
|
|
use rustc_attr_parsing::{AttributeParser, OmitDoc};
|
2019-12-29 17:23:55 +03:00
|
|
|
use rustc_expand::expand::AstFragment;
|
2024-05-07 14:43:23 +02:00
|
|
|
use rustc_hir as hir;
|
2023-11-21 23:40:23 +03:00
|
|
|
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
2019-11-03 14:36:59 +02:00
|
|
|
use rustc_hir::def_id::LocalDefId;
|
2021-06-25 20:43:04 +02:00
|
|
|
use rustc_span::hygiene::LocalExpnId;
|
2025-03-04 13:54:15 +11:00
|
|
|
use rustc_span::{Span, Symbol, sym};
|
2024-05-10 13:46:24 +10:00
|
|
|
use tracing::debug;
|
2016-04-14 12:14:03 +12:00
|
|
|
|
2024-11-25 18:42:10 +01:00
|
|
|
use crate::{ImplTraitContext, InvocationParent, Resolver};
|
2024-07-29 08:13:50 +10:00
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn collect_definitions(
|
2022-12-08 12:59:02 +00:00
|
|
|
resolver: &mut Resolver<'_, '_>,
|
2019-11-23 18:19:57 +03:00
|
|
|
fragment: &AstFragment,
|
2021-06-25 20:43:04 +02:00
|
|
|
expansion: LocalExpnId,
|
2019-11-23 18:19:57 +03:00
|
|
|
) {
|
2025-03-26 09:36:23 +00:00
|
|
|
let invocation_parent = resolver.invocation_parents[&expansion];
|
|
|
|
let mut visitor = DefCollector { resolver, expansion, invocation_parent };
|
2024-06-26 13:00:51 +03:00
|
|
|
fragment.visit_with(&mut visitor);
|
2019-11-23 18:19:57 +03:00
|
|
|
}
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Creates `DefId`s for nodes in the AST.
|
2024-09-10 16:19:40 +10:00
|
|
|
struct DefCollector<'a, 'ra, 'tcx> {
|
|
|
|
resolver: &'a mut Resolver<'ra, 'tcx>,
|
2025-03-26 09:36:23 +00:00
|
|
|
invocation_parent: InvocationParent,
|
2021-06-25 20:43:04 +02:00
|
|
|
expansion: LocalExpnId,
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
|
|
|
|
2024-09-10 16:19:40 +10:00
|
|
|
impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
|
2023-11-21 23:40:23 +03:00
|
|
|
fn create_def(
|
|
|
|
&mut self,
|
|
|
|
node_id: NodeId,
|
2025-03-04 13:54:15 +11:00
|
|
|
name: Option<Symbol>,
|
2023-11-21 23:40:23 +03:00
|
|
|
def_kind: DefKind,
|
|
|
|
span: Span,
|
|
|
|
) -> LocalDefId {
|
2025-03-26 09:36:23 +00:00
|
|
|
let parent_def = self.invocation_parent.parent_def;
|
2023-12-03 12:29:59 +03:00
|
|
|
debug!(
|
|
|
|
"create_def(node_id={:?}, def_kind={:?}, parent_def={:?})",
|
|
|
|
node_id, def_kind, parent_def
|
|
|
|
);
|
2024-02-14 14:49:16 +00:00
|
|
|
self.resolver
|
|
|
|
.create_def(
|
|
|
|
parent_def,
|
|
|
|
node_id,
|
|
|
|
name,
|
|
|
|
def_kind,
|
|
|
|
self.expansion.to_expn_id(),
|
|
|
|
span.with_parent(None),
|
|
|
|
)
|
|
|
|
.def_id()
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
|
|
|
|
2019-11-03 14:36:59 +02:00
|
|
|
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
|
2025-03-26 09:36:23 +00:00
|
|
|
let orig_parent_def = mem::replace(&mut self.invocation_parent.parent_def, parent_def);
|
2016-04-14 17:24:30 +12:00
|
|
|
f(self);
|
2025-03-26 09:36:23 +00:00
|
|
|
self.invocation_parent.parent_def = orig_parent_def;
|
2016-04-14 17:24:30 +12:00
|
|
|
}
|
2016-05-02 23:11:19 +03:00
|
|
|
|
2021-02-13 20:41:02 +01:00
|
|
|
fn with_impl_trait<F: FnOnce(&mut Self)>(
|
|
|
|
&mut self,
|
|
|
|
impl_trait_context: ImplTraitContext,
|
|
|
|
f: F,
|
|
|
|
) {
|
2025-03-26 09:36:23 +00:00
|
|
|
let orig_itc =
|
|
|
|
mem::replace(&mut self.invocation_parent.impl_trait_context, impl_trait_context);
|
2021-02-13 20:41:02 +01:00
|
|
|
f(self);
|
2025-03-26 09:36:23 +00:00
|
|
|
self.invocation_parent.impl_trait_context = orig_itc;
|
2021-02-13 20:41:02 +01:00
|
|
|
}
|
|
|
|
|
2021-03-16 00:36:07 +03:00
|
|
|
fn collect_field(&mut self, field: &'a FieldDef, index: Option<usize>) {
|
2019-11-23 14:16:38 +03:00
|
|
|
let index = |this: &Self| {
|
|
|
|
index.unwrap_or_else(|| {
|
|
|
|
let node_id = NodeId::placeholder_from_expn_id(this.expansion);
|
2020-06-20 19:59:29 +01:00
|
|
|
this.resolver.placeholder_field_indices[&node_id]
|
2019-11-23 14:16:38 +03:00
|
|
|
})
|
|
|
|
};
|
|
|
|
|
2019-09-14 17:36:27 +03:00
|
|
|
if field.is_placeholder {
|
2020-06-20 19:59:29 +01:00
|
|
|
let old_index = self.resolver.placeholder_field_indices.insert(field.id, index(self));
|
|
|
|
assert!(old_index.is_none(), "placeholder field index is reset for a node ID");
|
2019-09-14 17:36:27 +03:00
|
|
|
self.visit_macro_invoc(field.id);
|
|
|
|
} else {
|
2019-11-23 14:16:38 +03:00
|
|
|
let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
|
2025-03-04 13:54:15 +11:00
|
|
|
let def = self.create_def(field.id, Some(name), DefKind::Field, field.span);
|
2021-03-16 00:36:07 +03:00
|
|
|
self.with_parent(def, |this| visit::walk_field_def(this, field));
|
2019-09-14 17:36:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-10 01:41:47 +03:00
|
|
|
fn visit_macro_invoc(&mut self, id: NodeId) {
|
2021-02-13 20:41:02 +01:00
|
|
|
let id = id.placeholder_to_expn_id();
|
2025-03-26 09:36:23 +00:00
|
|
|
let old_parent = self.resolver.invocation_parents.insert(id, self.invocation_parent);
|
2020-06-20 19:59:29 +01:00
|
|
|
assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
|
2016-09-14 09:55:20 +00:00
|
|
|
}
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
|
|
|
|
2024-09-10 16:19:40 +10:00
|
|
|
impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_item(&mut self, i: &'a Item) {
|
2016-04-14 12:14:03 +12:00
|
|
|
// Pick the def data. This need not be unique, but the more
|
2018-05-22 14:31:56 +02:00
|
|
|
// information we encapsulate into, the better
|
2023-11-21 23:40:23 +03:00
|
|
|
let mut opt_macro_data = None;
|
2023-12-03 12:29:59 +03:00
|
|
|
let def_kind = match &i.kind {
|
|
|
|
ItemKind::Impl(i) => DefKind::Impl { of_trait: i.of_trait.is_some() },
|
|
|
|
ItemKind::ForeignMod(..) => DefKind::ForeignMod,
|
|
|
|
ItemKind::Mod(..) => DefKind::Mod,
|
|
|
|
ItemKind::Trait(..) => DefKind::Trait,
|
|
|
|
ItemKind::TraitAlias(..) => DefKind::TraitAlias,
|
|
|
|
ItemKind::Enum(..) => DefKind::Enum,
|
|
|
|
ItemKind::Struct(..) => DefKind::Struct,
|
|
|
|
ItemKind::Union(..) => DefKind::Union,
|
|
|
|
ItemKind::ExternCrate(..) => DefKind::ExternCrate,
|
|
|
|
ItemKind::TyAlias(..) => DefKind::TyAlias,
|
2024-05-07 14:43:23 +02:00
|
|
|
ItemKind::Static(s) => DefKind::Static {
|
|
|
|
safety: hir::Safety::Safe,
|
|
|
|
mutability: s.mutability,
|
|
|
|
nested: false,
|
|
|
|
},
|
2023-12-03 12:29:59 +03:00
|
|
|
ItemKind::Const(..) => DefKind::Const,
|
2023-11-26 15:57:31 +03:00
|
|
|
ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ItemKind::MacroDef(ident, def) => {
|
2024-11-20 17:12:56 -08:00
|
|
|
let edition = i.span.edition();
|
2025-02-09 22:49:33 +01:00
|
|
|
|
|
|
|
// FIXME(jdonszelmann) make one of these in the resolver?
|
|
|
|
// FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can.
|
|
|
|
// Does that prevents errors from happening? maybe
|
|
|
|
let parser = AttributeParser::new(
|
|
|
|
&self.resolver.tcx.sess,
|
|
|
|
self.resolver.tcx.features(),
|
|
|
|
Vec::new(),
|
|
|
|
);
|
2025-02-24 14:07:34 +01:00
|
|
|
let attrs = parser.parse_attribute_list(
|
|
|
|
&i.attrs,
|
|
|
|
i.span,
|
|
|
|
OmitDoc::Skip,
|
|
|
|
std::convert::identity,
|
|
|
|
);
|
2025-02-09 22:49:33 +01:00
|
|
|
|
2024-10-26 18:51:15 +03:00
|
|
|
let macro_data =
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
self.resolver.compile_macro(def, *ident, &attrs, i.span, i.id, edition);
|
2023-11-21 23:40:23 +03:00
|
|
|
let macro_kind = macro_data.ext.macro_kind();
|
|
|
|
opt_macro_data = Some(macro_data);
|
2023-12-03 12:29:59 +03:00
|
|
|
DefKind::Macro(macro_kind)
|
2018-06-06 15:50:59 -07:00
|
|
|
}
|
2023-12-03 12:29:59 +03:00
|
|
|
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
|
2024-04-24 19:56:56 +03:00
|
|
|
ItemKind::Use(..) => return visit::walk_item(self, i),
|
2024-03-15 14:21:03 +03:00
|
|
|
ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
|
|
|
|
return self.visit_macro_invoc(i.id);
|
|
|
|
}
|
2016-04-14 12:14:03 +12:00
|
|
|
};
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
let def_id =
|
|
|
|
self.create_def(i.id, i.kind.ident().map(|ident| ident.name), def_kind, i.span);
|
2016-04-14 12:14:03 +12:00
|
|
|
|
2023-11-21 23:40:23 +03:00
|
|
|
if let Some(macro_data) = opt_macro_data {
|
2023-11-24 23:39:42 +03:00
|
|
|
self.resolver.macro_map.insert(def_id.to_def_id(), macro_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.with_parent(def_id, |this| {
|
2021-02-13 20:41:02 +01:00
|
|
|
this.with_impl_trait(ImplTraitContext::Existential, |this| {
|
|
|
|
match i.kind {
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ItemKind::Struct(_, ref struct_def, _)
|
|
|
|
| ItemKind::Union(_, ref struct_def, _) => {
|
2021-02-13 20:41:02 +01:00
|
|
|
// If this is a unit or tuple-like struct, register the constructor.
|
2023-11-21 23:40:23 +03:00
|
|
|
if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) {
|
|
|
|
this.create_def(
|
|
|
|
ctor_node_id,
|
2025-03-04 13:54:15 +11:00
|
|
|
None,
|
2023-11-21 23:40:23 +03:00
|
|
|
DefKind::Ctor(CtorOf::Struct, ctor_kind),
|
|
|
|
i.span,
|
|
|
|
);
|
2021-02-13 20:41:02 +01:00
|
|
|
}
|
2016-04-14 17:24:30 +12:00
|
|
|
}
|
2021-02-13 20:41:02 +01:00
|
|
|
_ => {}
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
2021-02-13 20:41:02 +01:00
|
|
|
visit::walk_item(this, i);
|
|
|
|
})
|
2016-04-14 17:24:30 +12:00
|
|
|
});
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
|
|
|
|
2020-03-14 22:22:29 +03:00
|
|
|
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
2024-08-24 01:44:52 +00:00
|
|
|
match fn_kind {
|
2025-01-27 16:30:02 -08:00
|
|
|
FnKind::Fn(
|
|
|
|
_ctxt,
|
|
|
|
_vis,
|
2025-04-01 14:49:58 +11:00
|
|
|
Fn {
|
|
|
|
sig: FnSig { header, decl, span: _ }, ident, generics, contract, body, ..
|
|
|
|
},
|
2025-01-27 16:30:02 -08:00
|
|
|
) if let Some(coroutine_kind) = header.coroutine_kind => {
|
2025-04-01 14:49:58 +11:00
|
|
|
self.visit_ident(ident);
|
2024-08-24 01:44:52 +00:00
|
|
|
self.visit_fn_header(header);
|
|
|
|
self.visit_generics(generics);
|
2025-01-08 16:38:25 -08:00
|
|
|
if let Some(contract) = contract {
|
|
|
|
self.visit_contract(contract);
|
|
|
|
}
|
2024-08-24 01:44:52 +00:00
|
|
|
|
|
|
|
// For async functions, we need to create their inner defs inside of a
|
|
|
|
// closure to match their desugared representation. Besides that,
|
|
|
|
// we must mirror everything that `visit::walk_fn` below does.
|
|
|
|
let FnDecl { inputs, output } = &**decl;
|
|
|
|
for param in inputs {
|
|
|
|
self.visit_param(param);
|
|
|
|
}
|
|
|
|
|
|
|
|
let (return_id, return_span) = coroutine_kind.return_id();
|
2025-03-04 13:54:15 +11:00
|
|
|
let return_def = self.create_def(return_id, None, DefKind::OpaqueTy, return_span);
|
2024-08-24 01:44:52 +00:00
|
|
|
self.with_parent(return_def, |this| this.visit_fn_ret_ty(output));
|
|
|
|
|
|
|
|
// If this async fn has no body (i.e. it's an async fn signature in a trait)
|
|
|
|
// then the closure_def will never be used, and we should avoid generating a
|
|
|
|
// def-id for it.
|
|
|
|
if let Some(body) = body {
|
2025-03-04 13:54:15 +11:00
|
|
|
let closure_def =
|
|
|
|
self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span);
|
2024-08-24 01:44:52 +00:00
|
|
|
self.with_parent(closure_def, |this| this.visit_block(body));
|
2022-09-24 18:53:53 +00:00
|
|
|
}
|
2020-03-14 22:22:29 +03:00
|
|
|
}
|
2024-08-24 01:44:52 +00:00
|
|
|
FnKind::Closure(binder, Some(coroutine_kind), decl, body) => {
|
|
|
|
self.visit_closure_binder(binder);
|
|
|
|
visit::walk_fn_decl(self, decl);
|
2020-03-14 22:22:29 +03:00
|
|
|
|
2024-08-24 01:44:52 +00:00
|
|
|
// Async closures desugar to closures inside of closures, so
|
|
|
|
// we must create two defs.
|
|
|
|
let coroutine_def =
|
2025-03-04 13:54:15 +11:00
|
|
|
self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span);
|
2024-09-01 11:16:50 -04:00
|
|
|
self.with_parent(coroutine_def, |this| this.visit_expr(body));
|
2024-08-24 01:44:52 +00:00
|
|
|
}
|
|
|
|
_ => visit::walk_fn(self, fn_kind),
|
|
|
|
}
|
2020-03-14 22:22:29 +03:00
|
|
|
}
|
|
|
|
|
2017-09-26 23:04:00 +02:00
|
|
|
fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
|
2025-03-04 13:54:15 +11:00
|
|
|
self.create_def(id, None, DefKind::Use, use_tree.span);
|
2017-09-26 23:04:00 +02:00
|
|
|
visit::walk_use_tree(self, use_tree, id);
|
|
|
|
}
|
|
|
|
|
2023-11-28 15:43:07 +03:00
|
|
|
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
let (ident, def_kind) = match fi.kind {
|
2025-03-24 23:19:18 +00:00
|
|
|
ForeignItemKind::Static(box StaticItem {
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ident,
|
2025-03-24 23:19:18 +00:00
|
|
|
ty: _,
|
|
|
|
mutability,
|
|
|
|
expr: _,
|
|
|
|
safety,
|
|
|
|
define_opaque: _,
|
|
|
|
}) => {
|
2024-05-07 14:43:23 +02:00
|
|
|
let safety = match safety {
|
|
|
|
ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe,
|
|
|
|
ast::Safety::Safe(_) => hir::Safety::Safe,
|
|
|
|
};
|
|
|
|
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
(ident, DefKind::Static { safety, mutability, nested: false })
|
2024-05-07 14:43:23 +02:00
|
|
|
}
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
ForeignItemKind::Fn(box Fn { ident, .. }) => (ident, DefKind::Fn),
|
|
|
|
ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => (ident, DefKind::ForeignTy),
|
2023-11-28 15:43:07 +03:00
|
|
|
ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id),
|
2023-11-21 23:40:23 +03:00
|
|
|
};
|
2018-03-10 18:16:26 -08:00
|
|
|
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
let def = self.create_def(fi.id, Some(ident.name), def_kind, fi.span);
|
2016-04-14 12:14:03 +12:00
|
|
|
|
2024-04-24 20:31:51 +03:00
|
|
|
self.with_parent(def, |this| visit::walk_item(this, fi));
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
|
|
|
|
2019-08-24 13:54:40 -03:00
|
|
|
fn visit_variant(&mut self, v: &'a Variant) {
|
2019-09-09 09:26:25 -03:00
|
|
|
if v.is_placeholder {
|
|
|
|
return self.visit_macro_invoc(v.id);
|
|
|
|
}
|
2025-03-04 13:54:15 +11:00
|
|
|
let def = self.create_def(v.id, Some(v.ident.name), DefKind::Variant, v.span);
|
2019-03-21 23:38:50 +01:00
|
|
|
self.with_parent(def, |this| {
|
2023-11-21 23:40:23 +03:00
|
|
|
if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&v.data) {
|
|
|
|
this.create_def(
|
|
|
|
ctor_node_id,
|
2025-03-04 13:54:15 +11:00
|
|
|
None,
|
2023-11-21 23:40:23 +03:00
|
|
|
DefKind::Ctor(CtorOf::Variant, ctor_kind),
|
|
|
|
v.span,
|
|
|
|
);
|
2019-03-21 23:38:50 +01:00
|
|
|
}
|
2019-08-24 13:54:40 -03:00
|
|
|
visit::walk_variant(this, v)
|
2019-03-21 23:38:50 +01:00
|
|
|
});
|
2018-05-17 21:28:50 +03:00
|
|
|
}
|
|
|
|
|
2025-02-05 18:58:29 +08:00
|
|
|
fn visit_where_predicate(&mut self, pred: &'a WherePredicate) {
|
|
|
|
if pred.is_placeholder {
|
|
|
|
self.visit_macro_invoc(pred.id)
|
|
|
|
} else {
|
|
|
|
visit::walk_where_predicate(self, pred)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-24 13:54:40 -03:00
|
|
|
fn visit_variant_data(&mut self, data: &'a VariantData) {
|
2019-09-14 13:56:44 +03:00
|
|
|
// The assumption here is that non-`cfg` macro expansion cannot change field indices.
|
|
|
|
// It currently holds because only inert attributes are accepted on fields,
|
|
|
|
// and every such attribute expands into a single field after it's resolved.
|
2018-05-17 21:28:50 +03:00
|
|
|
for (index, field) in data.fields().iter().enumerate() {
|
2019-09-14 17:36:27 +03:00
|
|
|
self.collect_field(field, Some(index));
|
2018-05-17 21:28:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-27 20:07:09 +01:00
|
|
|
fn visit_generic_param(&mut self, param: &'a GenericParam) {
|
2019-09-09 09:26:25 -03:00
|
|
|
if param.is_placeholder {
|
|
|
|
self.visit_macro_invoc(param.id);
|
|
|
|
return;
|
|
|
|
}
|
2023-12-03 12:29:59 +03:00
|
|
|
let def_kind = match param.kind {
|
|
|
|
GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam,
|
|
|
|
GenericParamKind::Type { .. } => DefKind::TyParam,
|
|
|
|
GenericParamKind::Const { .. } => DefKind::ConstParam,
|
2018-05-26 19:16:21 +01:00
|
|
|
};
|
2025-03-04 13:54:15 +11:00
|
|
|
self.create_def(param.id, Some(param.ident.name), def_kind, param.ident.span);
|
2016-04-14 12:14:03 +12:00
|
|
|
|
2021-02-13 20:41:02 +01:00
|
|
|
// impl-Trait can happen inside generic parameters, like
|
|
|
|
// ```
|
|
|
|
// fn foo<U: Iterator<Item = impl Clone>>() {}
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// In that case, the impl-trait is lowered as an additional generic parameter.
|
2023-11-25 15:45:44 -05:00
|
|
|
self.with_impl_trait(ImplTraitContext::Universal, |this| {
|
2021-02-13 20:41:02 +01:00
|
|
|
visit::walk_generic_param(this, param)
|
|
|
|
});
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
|
|
|
|
2020-01-30 00:18:54 +01:00
|
|
|
fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
let (ident, def_kind) = match &i.kind {
|
|
|
|
AssocItemKind::Fn(box Fn { ident, .. })
|
|
|
|
| AssocItemKind::Delegation(box Delegation { ident, .. }) => (*ident, DefKind::AssocFn),
|
|
|
|
AssocItemKind::Const(box ConstItem { ident, .. }) => (*ident, DefKind::AssocConst),
|
|
|
|
AssocItemKind::Type(box TyAlias { ident, .. }) => (*ident, DefKind::AssocTy),
|
2024-03-15 14:21:03 +03:00
|
|
|
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
|
|
|
|
return self.visit_macro_invoc(i.id);
|
|
|
|
}
|
2016-04-14 12:14:03 +12:00
|
|
|
};
|
|
|
|
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-21 09:47:43 +11:00
|
|
|
let def = self.create_def(i.id, Some(ident.name), def_kind, i.span);
|
2020-01-30 00:18:54 +01:00
|
|
|
self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt));
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_pat(&mut self, pat: &'a Pat) {
|
2019-09-26 16:18:31 +01:00
|
|
|
match pat.kind {
|
2020-03-20 15:03:11 +01:00
|
|
|
PatKind::MacCall(..) => self.visit_macro_invoc(pat.id),
|
2017-04-29 14:39:47 +03:00
|
|
|
_ => visit::walk_pat(self, pat),
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-17 21:28:50 +03:00
|
|
|
fn visit_anon_const(&mut self, constant: &'a AnonConst) {
|
2025-03-04 13:54:15 +11:00
|
|
|
let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span);
|
2024-11-25 18:42:10 +01:00
|
|
|
self.with_parent(parent, |this| visit::walk_anon_const(this, constant));
|
2018-05-17 21:28:50 +03:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_expr(&mut self, expr: &'a Expr) {
|
2024-11-25 18:42:10 +01:00
|
|
|
let parent_def = match expr.kind {
|
|
|
|
ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
|
|
|
|
ExprKind::Closure(..) | ExprKind::Gen(..) => {
|
2025-03-04 13:54:15 +11:00
|
|
|
self.create_def(expr.id, None, DefKind::Closure, expr.span)
|
2024-11-25 18:42:10 +01:00
|
|
|
}
|
|
|
|
ExprKind::ConstBlock(ref constant) => {
|
|
|
|
for attr in &expr.attrs {
|
|
|
|
visit::walk_attribute(self, attr);
|
Fix anon const def-creation when macros are involved
Ever since #125915, some `ast::AnonConst`s turn into `hir::ConstArgKind::Path`s,
which don't have associated `DefId`s. To deal with the fact that we don't have
resolution information in `DefCollector`, we decided to implement a process
where if the anon const *appeared* to be trivial (i.e., `N` or `{ N }`), we
would avoid creating a def for it in `DefCollector`. If later, in AST lowering,
we realized it turned out to be a unit struct literal, or we were lowering it
to something that didn't use `hir::ConstArg`, we'd create its def there.
However, let's say we have a macro `m!()` that expands to a reference to a free
constant `FOO`. If we use `m!()` in the body of an anon const (e.g., `Foo<{ m!() }>`),
then in def collection, it appears to be a nontrivial anon const and we create
a def. But the macro expands to something that looks like a trivial const arg,
but is not, so in AST lowering we "fix" the mistake we assumed def collection
made and create a def for it. This causes a duplicate definition ICE.
The ideal long-term fix for this is a bit unclear. One option is to delay def
creation for all expression-like nodes until AST lowering (see #128844 for an
incomplete attempt at this). This would avoid issues like this one that are
caused by hacky workarounds. However, this approach has some downsides as well,
and the best approach is yet to be determined.
In the meantime, this PR fixes the bug by delaying def creation for anon consts
whose bodies are macro invocations until after we expand the macro and know
what is inside it. This is accomplished by adding information to create the
anon const's def to the data in `Resolver.invocation_parents`.
2024-08-15 14:36:10 -07:00
|
|
|
}
|
2025-03-04 13:54:15 +11:00
|
|
|
let def =
|
|
|
|
self.create_def(constant.id, None, DefKind::InlineConst, constant.value.span);
|
2024-11-25 18:42:10 +01:00
|
|
|
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
|
|
|
|
return;
|
|
|
|
}
|
2025-03-26 09:36:23 +00:00
|
|
|
_ => self.invocation_parent.parent_def,
|
2024-11-25 18:42:10 +01:00
|
|
|
};
|
Fix anon const def-creation when macros are involved
Ever since #125915, some `ast::AnonConst`s turn into `hir::ConstArgKind::Path`s,
which don't have associated `DefId`s. To deal with the fact that we don't have
resolution information in `DefCollector`, we decided to implement a process
where if the anon const *appeared* to be trivial (i.e., `N` or `{ N }`), we
would avoid creating a def for it in `DefCollector`. If later, in AST lowering,
we realized it turned out to be a unit struct literal, or we were lowering it
to something that didn't use `hir::ConstArg`, we'd create its def there.
However, let's say we have a macro `m!()` that expands to a reference to a free
constant `FOO`. If we use `m!()` in the body of an anon const (e.g., `Foo<{ m!() }>`),
then in def collection, it appears to be a nontrivial anon const and we create
a def. But the macro expands to something that looks like a trivial const arg,
but is not, so in AST lowering we "fix" the mistake we assumed def collection
made and create a def for it. This causes a duplicate definition ICE.
The ideal long-term fix for this is a bit unclear. One option is to delay def
creation for all expression-like nodes until AST lowering (see #128844 for an
incomplete attempt at this). This would avoid issues like this one that are
caused by hacky workarounds. However, this approach has some downsides as well,
and the best approach is yet to be determined.
In the meantime, this PR fixes the bug by delaying def creation for anon consts
whose bodies are macro invocations until after we expand the macro and know
what is inside it. This is accomplished by adding information to create the
anon const's def to the data in `Resolver.invocation_parents`.
2024-08-15 14:36:10 -07:00
|
|
|
|
2024-11-25 18:42:10 +01:00
|
|
|
self.with_parent(parent_def, |this| visit::walk_expr(this, expr))
|
2016-04-14 12:14:03 +12:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_ty(&mut self, ty: &'a Ty) {
|
2024-01-04 21:45:06 +08:00
|
|
|
match &ty.kind {
|
2020-10-04 22:48:57 +02:00
|
|
|
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
|
2024-08-24 01:44:52 +00:00
|
|
|
TyKind::ImplTrait(id, _) => {
|
|
|
|
// HACK: pprust breaks strings with newlines when the type
|
|
|
|
// gets too long. We don't want these to show up in compiler
|
|
|
|
// output or built artifacts, so replace them here...
|
|
|
|
// Perhaps we should instead format APITs more robustly.
|
|
|
|
let name = Symbol::intern(&pprust::ty_to_string(ty).replace('\n', " "));
|
2025-03-26 09:36:23 +00:00
|
|
|
let kind = match self.invocation_parent.impl_trait_context {
|
2024-08-24 01:44:52 +00:00
|
|
|
ImplTraitContext::Universal => DefKind::TyParam,
|
|
|
|
ImplTraitContext::Existential => DefKind::OpaqueTy,
|
2024-12-14 17:34:04 +00:00
|
|
|
ImplTraitContext::InBinding => return visit::walk_ty(self, ty),
|
2024-08-24 01:44:52 +00:00
|
|
|
};
|
2025-03-04 13:54:15 +11:00
|
|
|
let id = self.create_def(*id, Some(name), kind, ty.span);
|
2025-03-26 09:36:23 +00:00
|
|
|
match self.invocation_parent.impl_trait_context {
|
2024-08-24 01:44:52 +00:00
|
|
|
// Do not nest APIT, as we desugar them as `impl_trait: bounds`,
|
|
|
|
// so the `impl_trait` node is not a parent to `bounds`.
|
|
|
|
ImplTraitContext::Universal => visit::walk_ty(self, ty),
|
|
|
|
ImplTraitContext::Existential => {
|
|
|
|
self.with_parent(id, |this| visit::walk_ty(this, ty))
|
|
|
|
}
|
2024-12-14 17:34:04 +00:00
|
|
|
ImplTraitContext::InBinding => unreachable!(),
|
2024-08-24 01:44:52 +00:00
|
|
|
};
|
|
|
|
}
|
2020-10-04 22:48:57 +02:00
|
|
|
_ => visit::walk_ty(self, ty),
|
2016-07-22 18:56:22 +03:00
|
|
|
}
|
2016-05-02 23:11:19 +03:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
fn visit_stmt(&mut self, stmt: &'a Stmt) {
|
2019-09-26 17:34:50 +01:00
|
|
|
match stmt.kind {
|
2020-02-29 19:32:20 +03:00
|
|
|
StmtKind::MacCall(..) => self.visit_macro_invoc(stmt.id),
|
2024-12-14 17:34:04 +00:00
|
|
|
// FIXME(impl_trait_in_bindings): We don't really have a good way of
|
|
|
|
// introducing the right `ImplTraitContext` here for all the cases we
|
|
|
|
// care about, in case we want to introduce ITIB to other positions
|
|
|
|
// such as turbofishes (e.g. `foo::<impl Fn()>(|| {})`).
|
|
|
|
StmtKind::Let(ref local) => self.with_impl_trait(ImplTraitContext::InBinding, |this| {
|
|
|
|
visit::walk_local(this, local)
|
|
|
|
}),
|
2016-09-14 09:55:20 +00:00
|
|
|
_ => visit::walk_stmt(self, stmt),
|
|
|
|
}
|
|
|
|
}
|
2017-10-23 17:22:28 +09:00
|
|
|
|
2019-09-09 09:26:25 -03:00
|
|
|
fn visit_arm(&mut self, arm: &'a Arm) {
|
|
|
|
if arm.is_placeholder { self.visit_macro_invoc(arm.id) } else { visit::walk_arm(self, arm) }
|
|
|
|
}
|
|
|
|
|
2021-03-16 00:36:07 +03:00
|
|
|
fn visit_expr_field(&mut self, f: &'a ExprField) {
|
|
|
|
if f.is_placeholder {
|
|
|
|
self.visit_macro_invoc(f.id)
|
|
|
|
} else {
|
|
|
|
visit::walk_expr_field(self, f)
|
|
|
|
}
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
|
2021-03-16 00:36:07 +03:00
|
|
|
fn visit_pat_field(&mut self, fp: &'a PatField) {
|
2019-09-09 09:26:25 -03:00
|
|
|
if fp.is_placeholder {
|
|
|
|
self.visit_macro_invoc(fp.id)
|
|
|
|
} else {
|
2021-03-16 00:36:07 +03:00
|
|
|
visit::walk_pat_field(self, fp)
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_param(&mut self, p: &'a Param) {
|
2021-02-13 20:41:02 +01:00
|
|
|
if p.is_placeholder {
|
|
|
|
self.visit_macro_invoc(p.id)
|
|
|
|
} else {
|
2023-11-25 15:45:44 -05:00
|
|
|
self.with_impl_trait(ImplTraitContext::Universal, |this| visit::walk_param(this, p))
|
2021-02-13 20:41:02 +01:00
|
|
|
}
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
|
|
|
|
2019-09-14 13:56:44 +03:00
|
|
|
// This method is called only when we are visiting an individual field
|
|
|
|
// after expanding an attribute on it.
|
2021-03-16 00:36:07 +03:00
|
|
|
fn visit_field_def(&mut self, field: &'a FieldDef) {
|
2019-09-14 17:36:27 +03:00
|
|
|
self.collect_field(field, None);
|
2019-09-09 09:26:25 -03:00
|
|
|
}
|
2021-10-17 19:32:34 +03:00
|
|
|
|
|
|
|
fn visit_crate(&mut self, krate: &'a Crate) {
|
2022-01-05 16:09:55 +08:00
|
|
|
if krate.is_placeholder {
|
|
|
|
self.visit_macro_invoc(krate.id)
|
2021-10-17 19:32:34 +03:00
|
|
|
} else {
|
|
|
|
visit::walk_crate(self, krate)
|
|
|
|
}
|
|
|
|
}
|
2024-06-26 13:00:51 +03:00
|
|
|
|
|
|
|
fn visit_attribute(&mut self, attr: &'a Attribute) -> Self::Result {
|
2025-03-26 09:36:23 +00:00
|
|
|
let orig_in_attr = mem::replace(&mut self.invocation_parent.in_attr, true);
|
2024-06-26 13:00:51 +03:00
|
|
|
visit::walk_attribute(self, attr);
|
2025-03-26 09:36:23 +00:00
|
|
|
self.invocation_parent.in_attr = orig_in_attr;
|
2024-06-26 13:00:51 +03:00
|
|
|
}
|
2025-02-26 16:28:37 +00:00
|
|
|
|
|
|
|
fn visit_inline_asm(&mut self, asm: &'a InlineAsm) {
|
|
|
|
let InlineAsm {
|
|
|
|
asm_macro: _,
|
|
|
|
template: _,
|
|
|
|
template_strs: _,
|
|
|
|
operands,
|
|
|
|
clobber_abis: _,
|
|
|
|
options: _,
|
|
|
|
line_spans: _,
|
|
|
|
} = asm;
|
|
|
|
for (op, _span) in operands {
|
|
|
|
match op {
|
|
|
|
InlineAsmOperand::In { expr, reg: _ }
|
|
|
|
| InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ }
|
|
|
|
| InlineAsmOperand::InOut { expr, reg: _, late: _ } => {
|
|
|
|
self.visit_expr(expr);
|
|
|
|
}
|
|
|
|
InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {}
|
|
|
|
InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
|
|
|
|
self.visit_expr(in_expr);
|
|
|
|
if let Some(expr) = out_expr {
|
|
|
|
self.visit_expr(expr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
InlineAsmOperand::Const { anon_const } => {
|
|
|
|
let def = self.create_def(
|
|
|
|
anon_const.id,
|
2025-03-04 13:54:15 +11:00
|
|
|
None,
|
2025-02-26 16:28:37 +00:00
|
|
|
DefKind::InlineConst,
|
|
|
|
anon_const.value.span,
|
|
|
|
);
|
|
|
|
self.with_parent(def, |this| visit::walk_anon_const(this, anon_const));
|
|
|
|
}
|
|
|
|
InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym),
|
|
|
|
InlineAsmOperand::Label { block } => self.visit_block(block),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-06 22:18:39 +01:00
|
|
|
}
|