Skip to content

Commit b75baad

Browse files
committed
Auto merge of #78181 - GuillaumeGomez:sized-trait, r=jyn514
Add Sized trait display when implemented on type Fixes #24183. I'm not too happy about the hack I had to add in here, however, it seems like the `Sized` trait is **very** special. cc `@jyn514` r? `@ollie27`
2 parents 9b471a3 + 46f24c9 commit b75baad

File tree

3 files changed

+142
-90
lines changed

3 files changed

+142
-90
lines changed

src/librustdoc/clean/auto_trait.rs

+114-90
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,107 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
2929
AutoTraitFinder { cx }
3030
}
3131

32+
fn generate_for_trait(
33+
&mut self,
34+
ty: Ty<'tcx>,
35+
trait_def_id: DefId,
36+
param_env: ty::ParamEnv<'tcx>,
37+
param_env_def_id: DefId,
38+
f: &auto_trait::AutoTraitFinder<'tcx>,
39+
// If this is set, show only negative trait implementations, not positive ones.
40+
discard_positive_impl: bool,
41+
) -> Option<Item> {
42+
let tcx = self.cx.tcx;
43+
let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
44+
if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
45+
debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
46+
return None;
47+
}
48+
49+
let result = f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
50+
let region_data = info.region_data;
51+
52+
let names_map = tcx
53+
.generics_of(param_env_def_id)
54+
.params
55+
.iter()
56+
.filter_map(|param| match param.kind {
57+
ty::GenericParamDefKind::Lifetime => Some(param.name),
58+
_ => None,
59+
})
60+
.map(|name| (name, Lifetime(name)))
61+
.collect();
62+
let lifetime_predicates = Self::handle_lifetimes(&region_data, &names_map);
63+
let new_generics = self.param_env_to_generics(
64+
infcx.tcx,
65+
param_env_def_id,
66+
info.full_user_env,
67+
lifetime_predicates,
68+
info.vid_to_region,
69+
);
70+
71+
debug!(
72+
"find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
73+
finished with {:?}",
74+
param_env_def_id, trait_def_id, new_generics
75+
);
76+
77+
new_generics
78+
});
79+
80+
let negative_polarity;
81+
let new_generics = match result {
82+
AutoTraitResult::PositiveImpl(new_generics) => {
83+
negative_polarity = false;
84+
if discard_positive_impl {
85+
return None;
86+
}
87+
new_generics
88+
}
89+
AutoTraitResult::NegativeImpl => {
90+
negative_polarity = true;
91+
92+
// For negative impls, we use the generic params, but *not* the predicates,
93+
// from the original type. Otherwise, the displayed impl appears to be a
94+
// conditional negative impl, when it's really unconditional.
95+
//
96+
// For example, consider the struct Foo<T: Copy>(*mut T). Using
97+
// the original predicates in our impl would cause us to generate
98+
// `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
99+
// implements Send where T is not copy.
100+
//
101+
// Instead, we generate `impl !Send for Foo<T>`, which better
102+
// expresses the fact that `Foo<T>` never implements `Send`,
103+
// regardless of the choice of `T`.
104+
let params = (tcx.generics_of(param_env_def_id), ty::GenericPredicates::default())
105+
.clean(self.cx)
106+
.params;
107+
108+
Generics { params, where_predicates: Vec::new() }
109+
}
110+
AutoTraitResult::ExplicitImpl => return None,
111+
};
112+
113+
Some(Item {
114+
source: Span::dummy(),
115+
name: None,
116+
attrs: Default::default(),
117+
visibility: Inherited,
118+
def_id: self.cx.next_def_id(param_env_def_id.krate),
119+
kind: box ImplItem(Impl {
120+
unsafety: hir::Unsafety::Normal,
121+
generics: new_generics,
122+
provided_trait_methods: Default::default(),
123+
trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
124+
for_: ty.clean(self.cx),
125+
items: Vec::new(),
126+
negative_polarity,
127+
synthetic: true,
128+
blanket_impl: None,
129+
}),
130+
})
131+
}
132+
32133
// FIXME(eddyb) figure out a better way to pass information about
33134
// parametrization of `ty` than `param_env_def_id`.
34135
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> {
38139

39140
debug!("get_auto_trait_impls({:?})", ty);
40141
let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect();
41-
auto_traits
142+
let mut auto_traits: Vec<Item> = auto_traits
42143
.into_iter()
43144
.filter_map(|trait_def_id| {
44-
let trait_ref =
45-
ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
46-
if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
47-
debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
48-
return None;
49-
}
50-
51-
let result =
52-
f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
53-
let region_data = info.region_data;
54-
55-
let names_map = tcx
56-
.generics_of(param_env_def_id)
57-
.params
58-
.iter()
59-
.filter_map(|param| match param.kind {
60-
ty::GenericParamDefKind::Lifetime => Some(param.name),
61-
_ => None,
62-
})
63-
.map(|name| (name, Lifetime(name)))
64-
.collect();
65-
let lifetime_predicates = Self::handle_lifetimes(&region_data, &names_map);
66-
let new_generics = self.param_env_to_generics(
67-
infcx.tcx,
68-
param_env_def_id,
69-
info.full_user_env,
70-
lifetime_predicates,
71-
info.vid_to_region,
72-
);
73-
74-
debug!(
75-
"find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
76-
finished with {:?}",
77-
param_env_def_id, trait_def_id, new_generics
78-
);
79-
80-
new_generics
81-
});
82-
83-
let negative_polarity;
84-
let new_generics = match result {
85-
AutoTraitResult::PositiveImpl(new_generics) => {
86-
negative_polarity = false;
87-
new_generics
88-
}
89-
AutoTraitResult::NegativeImpl => {
90-
negative_polarity = true;
91-
92-
// For negative impls, we use the generic params, but *not* the predicates,
93-
// from the original type. Otherwise, the displayed impl appears to be a
94-
// conditional negative impl, when it's really unconditional.
95-
//
96-
// For example, consider the struct Foo<T: Copy>(*mut T). Using
97-
// the original predicates in our impl would cause us to generate
98-
// `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
99-
// implements Send where T is not copy.
100-
//
101-
// Instead, we generate `impl !Send for Foo<T>`, which better
102-
// expresses the fact that `Foo<T>` never implements `Send`,
103-
// regardless of the choice of `T`.
104-
let params =
105-
(tcx.generics_of(param_env_def_id), ty::GenericPredicates::default())
106-
.clean(self.cx)
107-
.params;
108-
109-
Generics { params, where_predicates: Vec::new() }
110-
}
111-
AutoTraitResult::ExplicitImpl => return None,
112-
};
113-
114-
Some(Item {
115-
source: Span::dummy(),
116-
name: None,
117-
attrs: Default::default(),
118-
visibility: Inherited,
119-
def_id: self.cx.next_def_id(param_env_def_id.krate),
120-
kind: box ImplItem(Impl {
121-
unsafety: hir::Unsafety::Normal,
122-
generics: new_generics,
123-
provided_trait_methods: Default::default(),
124-
trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
125-
for_: ty.clean(self.cx),
126-
items: Vec::new(),
127-
negative_polarity,
128-
synthetic: true,
129-
blanket_impl: None,
130-
}),
131-
})
145+
self.generate_for_trait(ty, trait_def_id, param_env, param_env_def_id, &f, false)
132146
})
133-
.collect()
147+
.collect();
148+
// We are only interested in case the type *doesn't* implement the Sized trait.
149+
if !ty.is_sized(self.cx.tcx.at(rustc_span::DUMMY_SP), param_env) {
150+
// In case `#![no_core]` is used, `sized_trait` returns nothing.
151+
if let Some(item) = self.cx.tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
152+
self.generate_for_trait(ty, sized_trait_did, param_env, param_env_def_id, &f, true)
153+
}) {
154+
auto_traits.push(item);
155+
}
156+
}
157+
auto_traits
134158
}
135159

136160
fn get_lifetime(region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime>) -> Lifetime {

src/librustdoc/core.rs

+11
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use std::{
3232
};
3333

3434
use crate::clean;
35+
use crate::clean::inline::build_external_trait;
3536
use crate::clean::{AttributesExt, MAX_DEF_IDX};
3637
use crate::config::{Options as RustdocOptions, RenderOptions};
3738
use crate::config::{OutputFormat, RenderInfo};
@@ -530,6 +531,16 @@ crate fn run_global_ctxt(
530531
module_trait_cache: RefCell::new(FxHashMap::default()),
531532
cache: Cache::default(),
532533
};
534+
535+
// Small hack to force the Sized trait to be present.
536+
//
537+
// Note that in case of `#![no_core]`, the trait is not available.
538+
if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
539+
let mut sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
540+
sized_trait.is_auto = true;
541+
ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait);
542+
}
543+
533544
debug!("crate: {:?}", tcx.hir().krate());
534545

535546
let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));

src/test/rustdoc/sized_trait.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![crate_name = "foo"]
2+
3+
// @has foo/struct.Bar.html
4+
// @!has - '//h3[@id="impl-Sized"]'
5+
pub struct Bar {
6+
a: u16,
7+
}
8+
9+
// @has foo/struct.Foo.html
10+
// @!has - '//h3[@id="impl-Sized"]'
11+
pub struct Foo<T: ?Sized>(T);
12+
13+
// @has foo/struct.Unsized.html
14+
// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
15+
pub struct Unsized {
16+
data: [u8],
17+
}

0 commit comments

Comments
 (0)