1use rustc_data_structures::fx::FxIndexMap;
2use rustc_hir::attrs::{EiiDecl, EiiImpl, EiiImplResolution};
3use rustc_hir::def_id::DefId;
4use rustc_hir::find_attr;
5use rustc_middle::bug;
6use rustc_middle::query::LocalCrate;
7use rustc_middle::ty::TyCtxt;
89// basically the map below but flattened out
10pub(crate) type EiiMapEncodedKeyValue = (DefId, (EiiDecl, Vec<(DefId, EiiImpl)>));
1112pub(crate) type EiiMap = FxIndexMap<
13DefId, // the defid of the foreign item associated with the eii
14(
15// the corresponding declaration
16EiiDecl,
17// all the given implementations, indexed by defid.
18 // We expect there to be only one, but collect them all to give errors if there are more
19 // (or if there are none) in the final crate we build.
20FxIndexMap<DefId, EiiImpl>,
21 ),
22>;
2324pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap {
25let mut eiis = EiiMap::default();
2627// Needed because Known only stores a DefId (not the full EiiDecl),
28 // and we can't call the externally_implementable_items query (cycle).
29let decls_by_foreign_item: FxIndexMap<DefId, EiiDecl> = tcx30 .hir_crate_items(())
31 .eiis()
32 .filter_map(|id| {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(id, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(EiiDeclaration(d)) => {
break 'done Some(*d);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(tcx, id, EiiDeclaration(d) => *d))
33 .map(|decl| (decl.foreign_item, decl))
34 .collect();
3536// iterate over all items in the current crate
37for id in tcx.hir_crate_items(()).eiis() {
38// if we find a new declaration, add it to the list without a known implementation
39if let Some(decl) = {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(id, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(EiiDeclaration(d)) => {
break 'done Some(*d);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(tcx, id, EiiDeclaration(d) => *d) {
40 eiis.entry(decl.foreign_item).or_insert((decl, Default::default()));
41 }
4243if let Some(i) = {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(id, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(EiiImpl(i)) => {
break 'done Some(i);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(tcx, id, EiiImpl(i) => i) {
44let (foreign_item, decl) = match i.resolution {
45 EiiImplResolution::Macro(macro_defid) => {
46// find the decl for this one if it wasn't in yet (maybe it's from the local crate? not very useful but not illegal)
47let Some(decl) = {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(macro_defid, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(EiiDeclaration(d)) => {
break 'done Some(*d);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(tcx, macro_defid, EiiDeclaration(d) => *d)else {
48// skip if it doesn't have eii_declaration (if we resolved to another macro that's not an EII)
49tcx.dcx()
50 .span_delayed_bug(i.span, "resolved to something that's not an EII");
51continue;
52 };
53 (decl.foreign_item, decl)
54 }
55// Recover the EiiDecl from the local lookup map.
56EiiImplResolution::Known(foreign_item_did) => {
57let decl = decls_by_foreign_item.get(&foreign_item_did).unwrap_or_else(|| {
58::rustc_middle::util::bug::bug_fmt(format_args!("EII impl has Known resolution but can\'t find EiiDeclaration for {0:?}",
foreign_item_did))bug!(
59"EII impl has Known resolution but can't find EiiDeclaration for {:?}",
60 foreign_item_did
61 )62 });
63 (foreign_item_did, *decl)
64 }
65 EiiImplResolution::Error(_eg) => continue,
66 };
6768 eiis.entry(foreign_item)
69 .or_insert_with(|| (decl, Default::default()))
70 .1
71.insert(id.into(), **i);
72 }
73 }
7475eiis76}