]> git.lizzy.rs Git - rust.git/blobdiff - src/librustdoc/passes/collect_trait_impls.rs
rustdoc: avoid including impl blocks with filled-in generics
[rust.git] / src / librustdoc / passes / collect_trait_impls.rs
index 9644e3d15fdfadbf366e86f6b6a81a88c466d2c0..0dc1c9d9663130ea46095484d6c4eaeb792b5b62 100644 (file)
@@ -9,7 +9,7 @@
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::DefIdTree;
+use rustc_middle::ty::{self, DefIdTree};
 use rustc_span::symbol::sym;
 
 crate const COLLECT_TRAIT_IMPLS: Pass = Pass {
         let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
         let mut attr_buf = Vec::new();
         for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
-            let mut parent = cx.tcx.parent(impl_def_id);
+            let mut parent = Some(cx.tcx.parent(impl_def_id));
             while let Some(did) = parent {
                 attr_buf.extend(
                     cx.tcx
-                        .get_attrs(did)
-                        .iter()
-                        .filter(|attr| attr.has_name(sym::doc))
+                        .get_attrs(did, sym::doc)
                         .filter(|attr| {
                             if let Some([attr]) = attr.meta_item_list().as_deref() {
                                 attr.has_name(sym::cfg)
@@ -65,7 +63,7 @@
                         })
                         .cloned(),
                 );
-                parent = cx.tcx.parent(did);
+                parent = cx.tcx.opt_parent(did);
             }
             inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local);
             attr_buf.clear();
             // Do not calculate blanket impl list for docs that are not going to be rendered.
             // While the `impl` blocks themselves are only in `libcore`, the module with `doc`
             // attached is directly included in `libstd` as well.
+            let tcx = cx.tcx;
             if did.is_local() {
-                for def_id in prim.impls(cx.tcx) {
+                for def_id in prim.impls(tcx).filter(|def_id| {
+                    // Avoid including impl blocks with filled-in generics.
+                    // https://github.com/rust-lang/rust/issues/94937
+                    //
+                    // FIXME(notriddle): https://github.com/rust-lang/rust/issues/97129
+                    //
+                    // This tactic of using inherent impl blocks for getting
+                    // auto traits and blanket impls is a hack. What we really
+                    // want is to check if `[T]` impls `Send`, which has
+                    // nothing to do with the inherent impl.
+                    //
+                    // Rustdoc currently uses these `impl` block as a source of
+                    // the `Ty`, as well as the `ParamEnv`, `SubstsRef`, and
+                    // `Generics`. To avoid relying on the `impl` block, these
+                    // things would need to be created from wholecloth, in a
+                    // form that is valid for use in type inference.
+                    let ty = tcx.type_of(def_id);
+                    match ty.kind() {
+                        ty::Slice(ty) => matches!(ty.kind(), ty::Param(..)),
+                        ty::Ref(_region, ty, _mutbl) => matches!(ty.kind(), ty::Param(..)),
+                        ty::RawPtr(ty::TypeAndMut { ty, .. }) => matches!(ty.kind(), ty::Param(..)),
+                        ty::Tuple(tys) => tys.iter().all(|ty| matches!(ty.kind(), ty::Param(..))),
+                        _ => true,
+                    }
+                }) {
                     let impls = get_auto_trait_and_blanket_impls(cx, def_id);
                     new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
                 }