|
3 | 3 | //! struct implements that trait. |
4 | 4 |
|
5 | 5 | use rustc_data_structures::fx::FxHashSet; |
| 6 | +use rustc_errors::FatalError; |
6 | 7 | use rustc_hir::attrs::{AttributeKind, DocAttribute}; |
7 | | -use rustc_hir::def_id::LOCAL_CRATE; |
| 8 | +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; |
8 | 9 | use rustc_hir::{Attribute, find_attr}; |
9 | | -use rustc_middle::ty; |
| 10 | +use rustc_middle::ty::{self, Ty, TyCtxt}; |
| 11 | +use rustc_span::kw; |
10 | 12 |
|
11 | 13 | use super::Pass; |
12 | 14 | use crate::clean::*; |
@@ -59,13 +61,14 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> |
59 | 61 | }); |
60 | 62 | } else { |
61 | 63 | 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 { |
69 | 72 | cx.with_param_env(impl_def_id, |cx| { |
70 | 73 | inline::build_impl(cx, impl_def_id, None, &mut new_items_external); |
71 | 74 | }); |
@@ -157,6 +160,105 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> |
157 | 160 | krate |
158 | 161 | } |
159 | 162 |
|
| 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 | + |
160 | 262 | struct SyntheticImplCollector<'a, 'tcx> { |
161 | 263 | cx: &'a mut DocContext<'tcx>, |
162 | 264 | impls: Vec<Item>, |
|
0 commit comments