Skip to main content

rustc_metadata/
eii.rs

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;
8
9// basically the map below but flattened out
10pub(crate) type EiiMapEncodedKeyValue = (DefId, (EiiDecl, Vec<(DefId, EiiImpl)>));
11
12pub(crate) type EiiMap = FxIndexMap<
13    DefId, // the defid of the foreign item associated with the eii
14    (
15        // the corresponding declaration
16        EiiDecl,
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.
20        FxIndexMap<DefId, EiiImpl>,
21    ),
22>;
23
24pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap {
25    let mut eiis = EiiMap::default();
26
27    // Needed because Known only stores a DefId (not the full EiiDecl),
28    // and we can't call the externally_implementable_items query (cycle).
29    let decls_by_foreign_item: FxIndexMap<DefId, EiiDecl> = tcx
30        .hir_crate_items(())
31        .eiis()
32        .filter_map(|id| {
    {
        'done:
            {
            for i in ::rustc_hir::attrs::HasAttrs::get_attrs(id, &tcx) {
                #[allow(unused_imports)]
                use ::rustc_hir::attrs::AttributeKind::*;
                let i: &::rustc_hir::Attribute = i;
                match i {
                    ::rustc_hir::Attribute::Parsed(EiiDeclaration(d)) => {
                        break 'done Some(*d);
                    }
                    ::rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, id, EiiDeclaration(d) => *d))
33        .map(|decl| (decl.foreign_item, decl))
34        .collect();
35
36    // iterate over all items in the current crate
37    for id in tcx.hir_crate_items(()).eiis() {
38        for i in {
    {
        'done:
            {
            for i in ::rustc_hir::attrs::HasAttrs::get_attrs(id, &tcx) {
                #[allow(unused_imports)]
                use ::rustc_hir::attrs::AttributeKind::*;
                let i: &::rustc_hir::Attribute = i;
                match i {
                    ::rustc_hir::Attribute::Parsed(EiiImpls(e)) => {
                        break 'done Some(e);
                    }
                    ::rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, id, EiiImpls(e) => e).into_flat_iter() {
39            let (foreign_item, decl) = match i.resolution {
40                EiiImplResolution::Macro(macro_defid) => {
41                    // 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)
42                    let Some(decl) = {
    {
        'done:
            {
            for i in
                ::rustc_hir::attrs::HasAttrs::get_attrs(macro_defid, &tcx) {
                #[allow(unused_imports)]
                use ::rustc_hir::attrs::AttributeKind::*;
                let i: &::rustc_hir::Attribute = i;
                match i {
                    ::rustc_hir::Attribute::Parsed(EiiDeclaration(d)) => {
                        break 'done Some(*d);
                    }
                    ::rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, macro_defid, EiiDeclaration(d) => *d) else {
43                        // skip if it doesn't have eii_declaration (if we resolved to another macro that's not an EII)
44                        tcx.dcx()
45                            .span_delayed_bug(i.span, "resolved to something that's not an EII");
46                        continue;
47                    };
48                    (decl.foreign_item, decl)
49                }
50                // Recover the EiiDecl from the local lookup map.
51                EiiImplResolution::Known(foreign_item_did) => {
52                    let decl = decls_by_foreign_item.get(&foreign_item_did).unwrap_or_else(|| {
53                        ::rustc_middle::util::bug::bug_fmt(format_args!("EII impl has Known resolution but can\'t find EiiDeclaration for {0:?}",
        foreign_item_did))bug!(
54                            "EII impl has Known resolution but can't find EiiDeclaration for {:?}",
55                            foreign_item_did
56                        )
57                    });
58                    (foreign_item_did, *decl)
59                }
60                EiiImplResolution::Error(_eg) => continue,
61            };
62
63            eiis.entry(foreign_item)
64                .or_insert_with(|| (decl, Default::default()))
65                .1
66                .insert(id.into(), *i);
67        }
68
69        // if we find a new declaration, add it to the list without a known implementation
70        if let Some(decl) = {
    {
        'done:
            {
            for i in ::rustc_hir::attrs::HasAttrs::get_attrs(id, &tcx) {
                #[allow(unused_imports)]
                use ::rustc_hir::attrs::AttributeKind::*;
                let i: &::rustc_hir::Attribute = i;
                match i {
                    ::rustc_hir::Attribute::Parsed(EiiDeclaration(d)) => {
                        break 'done Some(*d);
                    }
                    ::rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, id, EiiDeclaration(d) => *d) {
71            eiis.entry(decl.foreign_item).or_insert((decl, Default::default()));
72        }
73    }
74
75    eiis
76}