about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2021-02-18 20:46:07 +0100
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2021-02-19 22:38:07 +0100
commitd20e05b78b39b67f2767911bf1c9610160924fba (patch)
tree294fe2bfa702309e09525aa2cf183f03fc262782
parent9b471a3f5fe57e5c6e08acf665f2094422415a3d (diff)
downloadrust-d20e05b78b39b67f2767911bf1c9610160924fba.tar.gz
rust-d20e05b78b39b67f2767911bf1c9610160924fba.zip
Show negative implementation of Sized trait
-rw-r--r--src/librustdoc/clean/auto_trait.rs204
-rw-r--r--src/librustdoc/core.rs11
2 files changed, 125 insertions, 90 deletions
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index d43378081ce..711b0298565 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -29,6 +29,107 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
         AutoTraitFinder { cx }
     }
 
+    fn generate_for_trait(
+        &mut self,
+        ty: Ty<'tcx>,
+        trait_def_id: DefId,
+        param_env: ty::ParamEnv<'tcx>,
+        param_env_def_id: DefId,
+        f: &auto_trait::AutoTraitFinder<'tcx>,
+        // If this is set, show only negative trait implementations, not positive ones.
+        discard_positive_impl: bool,
+    ) -> Option<Item> {
+        let tcx = self.cx.tcx;
+        let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
+        if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
+            debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
+            return None;
+        }
+
+        let result = f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
+            let region_data = info.region_data;
+
+            let names_map = tcx
+                .generics_of(param_env_def_id)
+                .params
+                .iter()
+                .filter_map(|param| match param.kind {
+                    ty::GenericParamDefKind::Lifetime => Some(param.name),
+                    _ => None,
+                })
+                .map(|name| (name, Lifetime(name)))
+                .collect();
+            let lifetime_predicates = Self::handle_lifetimes(&region_data, &names_map);
+            let new_generics = self.param_env_to_generics(
+                infcx.tcx,
+                param_env_def_id,
+                info.full_user_env,
+                lifetime_predicates,
+                info.vid_to_region,
+            );
+
+            debug!(
+                "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
+                    finished with {:?}",
+                param_env_def_id, trait_def_id, new_generics
+            );
+
+            new_generics
+        });
+
+        let negative_polarity;
+        let new_generics = match result {
+            AutoTraitResult::PositiveImpl(new_generics) => {
+                negative_polarity = false;
+                if discard_positive_impl {
+                    return None;
+                }
+                new_generics
+            }
+            AutoTraitResult::NegativeImpl => {
+                negative_polarity = true;
+
+                // For negative impls, we use the generic params, but *not* the predicates,
+                // from the original type. Otherwise, the displayed impl appears to be a
+                // conditional negative impl, when it's really unconditional.
+                //
+                // For example, consider the struct Foo<T: Copy>(*mut T). Using
+                // the original predicates in our impl would cause us to generate
+                // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
+                // implements Send where T is not copy.
+                //
+                // Instead, we generate `impl !Send for Foo<T>`, which better
+                // expresses the fact that `Foo<T>` never implements `Send`,
+                // regardless of the choice of `T`.
+                let params = (tcx.generics_of(param_env_def_id), ty::GenericPredicates::default())
+                    .clean(self.cx)
+                    .params;
+
+                Generics { params, where_predicates: Vec::new() }
+            }
+            AutoTraitResult::ExplicitImpl => return None,
+        };
+
+        Some(Item {
+            source: Span::dummy(),
+            name: None,
+            attrs: Default::default(),
+            visibility: Inherited,
+            def_id: self.cx.next_def_id(param_env_def_id.krate),
+            kind: box ImplItem(Impl {
+                unsafety: hir::Unsafety::Normal,
+                generics: new_generics,
+                provided_trait_methods: Default::default(),
+                trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
+                for_: ty.clean(self.cx),
+                items: Vec::new(),
+                negative_polarity,
+                synthetic: true,
+                blanket_impl: None,
+            }),
+        })
+    }
+
     // FIXME(eddyb) figure out a better way to pass information about
     // parametrization of `ty` than `param_env_def_id`.
     crate fn get_auto_trait_impls(&mut self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
@@ -38,99 +139,22 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
 
         debug!("get_auto_trait_impls({:?})", ty);
         let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect();
-        auto_traits
+        let mut auto_traits: Vec<Item> = auto_traits
             .into_iter()
             .filter_map(|trait_def_id| {
-                let trait_ref =
-                    ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
-                if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
-                    debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
-                    return None;
-                }
-
-                let result =
-                    f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
-                        let region_data = info.region_data;
-
-                        let names_map = tcx
-                            .generics_of(param_env_def_id)
-                            .params
-                            .iter()
-                            .filter_map(|param| match param.kind {
-                                ty::GenericParamDefKind::Lifetime => Some(param.name),
-                                _ => None,
-                            })
-                            .map(|name| (name, Lifetime(name)))
-                            .collect();
-                        let lifetime_predicates = Self::handle_lifetimes(&region_data, &names_map);
-                        let new_generics = self.param_env_to_generics(
-                            infcx.tcx,
-                            param_env_def_id,
-                            info.full_user_env,
-                            lifetime_predicates,
-                            info.vid_to_region,
-                        );
-
-                        debug!(
-                            "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
-                            finished with {:?}",
-                            param_env_def_id, trait_def_id, new_generics
-                        );
-
-                        new_generics
-                    });
-
-                let negative_polarity;
-                let new_generics = match result {
-                    AutoTraitResult::PositiveImpl(new_generics) => {
-                        negative_polarity = false;
-                        new_generics
-                    }
-                    AutoTraitResult::NegativeImpl => {
-                        negative_polarity = true;
-
-                        // For negative impls, we use the generic params, but *not* the predicates,
-                        // from the original type. Otherwise, the displayed impl appears to be a
-                        // conditional negative impl, when it's really unconditional.
-                        //
-                        // For example, consider the struct Foo<T: Copy>(*mut T). Using
-                        // the original predicates in our impl would cause us to generate
-                        // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
-                        // implements Send where T is not copy.
-                        //
-                        // Instead, we generate `impl !Send for Foo<T>`, which better
-                        // expresses the fact that `Foo<T>` never implements `Send`,
-                        // regardless of the choice of `T`.
-                        let params =
-                            (tcx.generics_of(param_env_def_id), ty::GenericPredicates::default())
-                                .clean(self.cx)
-                                .params;
-
-                        Generics { params, where_predicates: Vec::new() }
-                    }
-                    AutoTraitResult::ExplicitImpl => return None,
-                };
-
-                Some(Item {
-                    source: Span::dummy(),
-                    name: None,
-                    attrs: Default::default(),
-                    visibility: Inherited,
-                    def_id: self.cx.next_def_id(param_env_def_id.krate),
-                    kind: box ImplItem(Impl {
-                        unsafety: hir::Unsafety::Normal,
-                        generics: new_generics,
-                        provided_trait_methods: Default::default(),
-                        trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
-                        for_: ty.clean(self.cx),
-                        items: Vec::new(),
-                        negative_polarity,
-                        synthetic: true,
-                        blanket_impl: None,
-                    }),
-                })
+                self.generate_for_trait(ty, trait_def_id, param_env, param_env_def_id, &f, false)
             })
-            .collect()
+            .collect();
+        // We are only interested in case the type *doesn't* implement the Sized trait.
+        if !ty.is_sized(self.cx.tcx.at(rustc_span::DUMMY_SP), param_env) {
+            // In case `#![no_core]` is used, `sized_trait` returns nothing.
+            if let Some(item) = self.cx.tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
+                self.generate_for_trait(ty, sized_trait_did, param_env, param_env_def_id, &f, true)
+            }) {
+                auto_traits.push(item);
+            }
+        }
+        auto_traits
     }
 
     fn get_lifetime(region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime>) -> Lifetime {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 4517eda9b33..1c2d2ad626c 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -32,6 +32,7 @@ use std::{
 };
 
 use crate::clean;
+use crate::clean::inline::build_external_trait;
 use crate::clean::{AttributesExt, MAX_DEF_IDX};
 use crate::config::{Options as RustdocOptions, RenderOptions};
 use crate::config::{OutputFormat, RenderInfo};
@@ -530,6 +531,16 @@ crate fn run_global_ctxt(
         module_trait_cache: RefCell::new(FxHashMap::default()),
         cache: Cache::default(),
     };
+
+    // Small hack to force the Sized trait to be present.
+    //
+    // Note that in case of `#![no_core]`, the trait is not available.
+    if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
+        let mut sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
+        sized_trait.is_auto = true;
+        ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait);
+    }
+
     debug!("crate: {:?}", tcx.hir().krate());
 
     let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));