Show negative implementation of Sized trait
This commit is contained in:
parent
9b471a3f5f
commit
d20e05b78b
@ -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(®ion_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(®ion_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 {
|
||||
|
@ -32,6 +32,7 @@
|
||||
};
|
||||
|
||||
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 @@ pub(crate) fn init_lints<F>(
|
||||
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));
|
||||
|
Loading…
Reference in New Issue
Block a user