Skip to content

Commit 5377944

Browse files
committed
wip2
1 parent 384aa67 commit 5377944

1 file changed

Lines changed: 111 additions & 9 deletions

File tree

src/librustdoc/passes/collect_trait_impls.rs

Lines changed: 111 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
//! struct implements that trait.
44
55
use rustc_data_structures::fx::FxHashSet;
6+
use rustc_errors::FatalError;
67
use rustc_hir::attrs::{AttributeKind, DocAttribute};
7-
use rustc_hir::def_id::LOCAL_CRATE;
8+
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
89
use rustc_hir::{Attribute, find_attr};
9-
use rustc_middle::ty;
10+
use rustc_middle::ty::{self, Ty, TyCtxt};
11+
use rustc_span::kw;
1012

1113
use super::Pass;
1214
use crate::clean::*;
@@ -59,13 +61,14 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
5961
});
6062
} else {
6163
let self_ty = tcx.type_of(impl_def_id).instantiate_identity().skip_norm_wip();
62-
let self_ty =
63-
clean_middle_ty(ty::Binder::dummy(self_ty), cx, Some(impl_def_id), None);
64-
if self_ty.is_full_generic()
65-
|| self_ty
66-
.def_id(&cx.cache)
67-
.is_some_and(|did| crate_items.contains(&ItemId::DefId(did)))
68-
{
64+
let self_ty_head =
65+
SelfTyHead::of(ty::Binder::dummy(self_ty), tcx, Some(impl_def_id));
66+
let keep_impl = match self_ty_head {
67+
SelfTyHead::Generic => true,
68+
SelfTyHead::Item(def_id) => crate_items.contains(&ItemId::DefId(def_id)),
69+
SelfTyHead::Primitive | SelfTyHead::Other => false,
70+
};
71+
if keep_impl {
6972
cx.with_param_env(impl_def_id, |cx| {
7073
inline::build_impl(cx, impl_def_id, None, &mut new_items_external);
7174
});
@@ -157,6 +160,105 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
157160
krate
158161
}
159162

163+
enum SelfTyHead {
164+
Generic,
165+
Primitive,
166+
Item(DefId),
167+
Other,
168+
}
169+
170+
impl SelfTyHead {
171+
fn of<'tcx>(
172+
bound_ty: ty::Binder<'tcx, Ty<'tcx>>,
173+
tcx: TyCtxt<'tcx>,
174+
parent: Option<DefId>,
175+
) -> Self {
176+
match *bound_ty.skip_binder().kind() {
177+
ty::Never => Self::Primitive,
178+
ty::Bool => Self::Primitive,
179+
ty::Char => Self::Primitive,
180+
ty::Int(..) => Self::Primitive,
181+
ty::Uint(..) => Self::Primitive,
182+
ty::Float(..) => Self::Primitive,
183+
ty::Str => Self::Primitive,
184+
ty::Slice(..) => Self::Primitive,
185+
ty::Pat(ty, _) => Self::of(bound_ty.rebind(ty), tcx, parent),
186+
ty::Array(..) => Self::Primitive,
187+
ty::RawPtr(..) => Self::Primitive,
188+
ty::Ref(_, ty, _) => match Self::of(bound_ty.rebind(ty), tcx, parent) {
189+
Self::Generic => Self::Primitive,
190+
head => head,
191+
},
192+
ty::FnDef(..) | ty::FnPtr(..) => Self::Primitive,
193+
ty::UnsafeBinder(_) => Self::Other,
194+
ty::Adt(def, _) => Self::Item(def.did()),
195+
ty::Foreign(did) => Self::Item(did),
196+
ty::Dynamic(obj, _) => {
197+
// HACK: pick the first `did` as the `did` of the trait object. Someone
198+
// might want to implement "native" support for marker-trait-only
199+
// trait objects.
200+
let mut dids = obj.auto_traits();
201+
let did = obj
202+
.principal_def_id()
203+
.or_else(|| dids.next())
204+
.unwrap_or_else(|| panic!("found trait object `{obj:?}` with no traits?"));
205+
Self::Item(did)
206+
}
207+
ty::Tuple(_) => Self::Primitive,
208+
209+
ty::Alias(_, alias_ty @ ty::AliasTy { kind: ty::Projection { def_id }, .. }) => {
210+
if tcx.is_impl_trait_in_trait(def_id) {
211+
Self::Other
212+
} else {
213+
Self::of(bound_ty.rebind(alias_ty.self_ty()), tcx, parent)
214+
}
215+
}
216+
217+
ty::Alias(_, alias_ty @ ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {
218+
let alias_ty = bound_ty.rebind(alias_ty);
219+
Self::of(alias_ty.map_bound(|ty| ty.self_ty()), tcx, parent)
220+
}
221+
222+
ty::Alias(_, ty::AliasTy { kind: ty::Free { def_id }, args, .. }) => {
223+
if tcx.features().checked_type_aliases() {
224+
// Free type alias `data` represents the `type X` in `type X = Y`. If we need `Y`,
225+
// we need to use `type_of`.
226+
Self::Item(def_id)
227+
} else {
228+
let ty = tcx.type_of(def_id).instantiate(tcx, args).skip_norm_wip();
229+
Self::of(bound_ty.rebind(ty), tcx, parent)
230+
}
231+
}
232+
233+
ty::Param(ref p) => {
234+
// FIXME: there's a slight behavior difference from clean_middle_ty here
235+
// since here we represent impl traits as Generic not ImplTrait.
236+
// probably doesn't matter for collect trait impls since impl trait
237+
// can't be a self ty
238+
if p.name == kw::SelfUpper { Self::Other } else { Self::Generic }
239+
}
240+
241+
ty::Bound(_, ref ty) => match ty.kind {
242+
ty::BoundTyKind::Param(_) => Self::Generic,
243+
ty::BoundTyKind::Anon => panic!("unexpected anonymous bound type variable"),
244+
},
245+
246+
ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
247+
panic!("should not appear as impl self ty")
248+
}
249+
250+
ty::Closure(..) => panic!("Closure"),
251+
ty::CoroutineClosure(..) => panic!("CoroutineClosure"),
252+
ty::Coroutine(..) => panic!("Coroutine"),
253+
ty::Placeholder(..) => panic!("Placeholder"),
254+
ty::CoroutineWitness(..) => panic!("CoroutineWitness"),
255+
ty::Infer(..) => panic!("Infer"),
256+
257+
ty::Error(_) => FatalError.raise(),
258+
}
259+
}
260+
}
261+
160262
struct SyntheticImplCollector<'a, 'tcx> {
161263
cx: &'a mut DocContext<'tcx>,
162264
impls: Vec<Item>,

0 commit comments

Comments
 (0)