about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2022-04-26 16:40:42 +0200
committerGuillaume Gomez <guillaume.gomez@huawei.com>2022-05-15 13:43:33 +0200
commit2e1369c198e27da9eec015a9e11088e431feb50b (patch)
tree6dc8da4a3d2f1a30ee751e04b1435216a43e5236
parent4054c0f3e6cecddadcc2aa19d7c97efed5611a4b (diff)
downloadrust-2e1369c198e27da9eec015a9e11088e431feb50b.tar.gz
rust-2e1369c198e27da9eec015a9e11088e431feb50b.zip
Prevent to recompute `should_show_cast` by passing down `self_def_id`
-rw-r--r--src/librustdoc/clean/mod.rs388
1 files changed, 191 insertions, 197 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e133372bc23..faac3a519af 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -379,19 +379,31 @@ impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
     }
 }
 
+fn clean_projection<'tcx>(
+    ty: ty::ProjectionTy<'tcx>,
+    cx: &mut DocContext<'_>,
+    def_id: Option<DefId>,
+) -> Type {
+    let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
+    let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
+    let self_type = ty.self_ty().clean(cx);
+    let self_def_id = if let Some(def_id) = def_id {
+        cx.tcx.opt_parent(def_id).or(Some(def_id))
+    } else {
+        self_type.def_id(&cx.cache)
+    };
+    let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
+    Type::QPath {
+        assoc: Box::new(projection_to_path_segment(ty, cx)),
+        should_show_cast,
+        self_type: box self_type,
+        trait_,
+    }
+}
+
 impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Type {
-        let lifted = self.lift_to_tcx(cx.tcx).unwrap();
-        let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
-        let self_type = self.self_ty().clean(cx);
-        let self_def_id = self_type.def_id(&cx.cache);
-        let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
-        Type::QPath {
-            assoc: Box::new(projection_to_path_segment(*self, cx)),
-            should_show_cast,
-            self_type: box self_type,
-            trait_,
-        }
+        clean_projection(*self, cx, None)
     }
 }
 
@@ -422,23 +434,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
             }
             ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
                 let default = if has_default {
-                    let mut default = cx.tcx.type_of(self.def_id).clean(cx);
-
-                    // We need to reassign the `self_def_id`, if there's a parent (which is the
-                    // `Self` type), so we can properly render `<Self as X>` casts, because the
-                    // information about which type `Self` is, is only present here, but not in
-                    // the cleaning process of the type itself. To resolve this and have the
-                    // `self_def_id` set, we override it here.
-                    // See https://github.com/rust-lang/rust/issues/85454
-                    if let QPath { ref mut should_show_cast, ref trait_, ref self_type, .. } =
-                        default
-                    {
-                        let self_def_id = cx.tcx.parent(self.def_id);
-                        *should_show_cast =
-                            compute_should_show_cast(self_def_id, trait_, self_type);
-                    }
-
-                    Some(default)
+                    Some(clean_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id)))
                 } else {
                     None
                 };
@@ -1534,196 +1530,194 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
     }
 }
 
-impl<'tcx> Clean<Type> for Ty<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
-        trace!("cleaning type: {:?}", self);
-        let ty = normalize(cx, *self).unwrap_or(*self);
-        match *ty.kind() {
-            ty::Never => Primitive(PrimitiveType::Never),
-            ty::Bool => Primitive(PrimitiveType::Bool),
-            ty::Char => Primitive(PrimitiveType::Char),
-            ty::Int(int_ty) => Primitive(int_ty.into()),
-            ty::Uint(uint_ty) => Primitive(uint_ty.into()),
-            ty::Float(float_ty) => Primitive(float_ty.into()),
-            ty::Str => Primitive(PrimitiveType::Str),
-            ty::Slice(ty) => Slice(box ty.clean(cx)),
-            ty::Array(ty, n) => {
-                let mut n = cx.tcx.lift(n).expect("array lift failed");
-                n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
-                let n = print_const(cx, n);
-                Array(box ty.clean(cx), n)
-            }
-            ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)),
-            ty::Ref(r, ty, mutbl) => {
-                BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) }
-            }
-            ty::FnDef(..) | ty::FnPtr(_) => {
-                let ty = cx.tcx.lift(*self).expect("FnPtr lift failed");
-                let sig = ty.fn_sig(cx.tcx);
-                let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
-                BareFunction(box BareFunctionDecl {
-                    unsafety: sig.unsafety(),
-                    generic_params: Vec::new(),
-                    decl,
-                    abi: sig.abi(),
-                })
-            }
-            ty::Adt(def, substs) => {
-                let did = def.did();
-                let kind = match def.adt_kind() {
-                    AdtKind::Struct => ItemType::Struct,
-                    AdtKind::Union => ItemType::Union,
-                    AdtKind::Enum => ItemType::Enum,
-                };
-                inline::record_extern_fqn(cx, did, kind);
-                let path = external_path(cx, did, false, vec![], substs);
-                Type::Path { path }
-            }
-            ty::Foreign(did) => {
-                inline::record_extern_fqn(cx, did, ItemType::ForeignType);
-                let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
-                Type::Path { path }
-            }
-            ty::Dynamic(obj, ref reg) => {
-                // HACK: pick the first `did` as the `did` of the trait object. Someone
-                // might want to implement "native" support for marker-trait-only
-                // trait objects.
-                let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
-                let did = dids
-                    .next()
-                    .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", self));
-                let substs = match obj.principal() {
-                    Some(principal) => principal.skip_binder().substs,
-                    // marker traits have no substs.
-                    _ => cx.tcx.intern_substs(&[]),
-                };
+fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'_>, def_id: Option<DefId>) -> Type {
+    trace!("cleaning type: {:?}", this);
+    let ty = normalize(cx, this).unwrap_or(this);
+    match *ty.kind() {
+        ty::Never => Primitive(PrimitiveType::Never),
+        ty::Bool => Primitive(PrimitiveType::Bool),
+        ty::Char => Primitive(PrimitiveType::Char),
+        ty::Int(int_ty) => Primitive(int_ty.into()),
+        ty::Uint(uint_ty) => Primitive(uint_ty.into()),
+        ty::Float(float_ty) => Primitive(float_ty.into()),
+        ty::Str => Primitive(PrimitiveType::Str),
+        ty::Slice(ty) => Slice(box ty.clean(cx)),
+        ty::Array(ty, n) => {
+            let mut n = cx.tcx.lift(n).expect("array lift failed");
+            n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
+            let n = print_const(cx, n);
+            Array(box ty.clean(cx), n)
+        }
+        ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)),
+        ty::Ref(r, ty, mutbl) => {
+            BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) }
+        }
+        ty::FnDef(..) | ty::FnPtr(_) => {
+            let ty = cx.tcx.lift(this).expect("FnPtr lift failed");
+            let sig = ty.fn_sig(cx.tcx);
+            let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
+            BareFunction(box BareFunctionDecl {
+                unsafety: sig.unsafety(),
+                generic_params: Vec::new(),
+                decl,
+                abi: sig.abi(),
+            })
+        }
+        ty::Adt(def, substs) => {
+            let did = def.did();
+            let kind = match def.adt_kind() {
+                AdtKind::Struct => ItemType::Struct,
+                AdtKind::Union => ItemType::Union,
+                AdtKind::Enum => ItemType::Enum,
+            };
+            inline::record_extern_fqn(cx, did, kind);
+            let path = external_path(cx, did, false, vec![], substs);
+            Type::Path { path }
+        }
+        ty::Foreign(did) => {
+            inline::record_extern_fqn(cx, did, ItemType::ForeignType);
+            let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
+            Type::Path { path }
+        }
+        ty::Dynamic(obj, ref reg) => {
+            // HACK: pick the first `did` as the `did` of the trait object. Someone
+            // might want to implement "native" support for marker-trait-only
+            // trait objects.
+            let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
+            let did = dids
+                .next()
+                .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this));
+            let substs = match obj.principal() {
+                Some(principal) => principal.skip_binder().substs,
+                // marker traits have no substs.
+                _ => cx.tcx.intern_substs(&[]),
+            };
 
-                inline::record_extern_fqn(cx, did, ItemType::Trait);
+            inline::record_extern_fqn(cx, did, ItemType::Trait);
 
-                let lifetime = reg.clean(cx);
-                let mut bounds = vec![];
+            let lifetime = reg.clean(cx);
+            let mut bounds = vec![];
 
-                for did in dids {
-                    let empty = cx.tcx.intern_substs(&[]);
-                    let path = external_path(cx, did, false, vec![], empty);
-                    inline::record_extern_fqn(cx, did, ItemType::Trait);
-                    let bound = PolyTrait { trait_: path, generic_params: Vec::new() };
-                    bounds.push(bound);
-                }
+            for did in dids {
+                let empty = cx.tcx.intern_substs(&[]);
+                let path = external_path(cx, did, false, vec![], empty);
+                inline::record_extern_fqn(cx, did, ItemType::Trait);
+                let bound = PolyTrait { trait_: path, generic_params: Vec::new() };
+                bounds.push(bound);
+            }
 
-                let mut bindings = vec![];
-                for pb in obj.projection_bounds() {
-                    bindings.push(TypeBinding {
-                        assoc: projection_to_path_segment(
-                            pb.skip_binder()
-                                .lift_to_tcx(cx.tcx)
-                                .unwrap()
-                                // HACK(compiler-errors): Doesn't actually matter what self
-                                // type we put here, because we're only using the GAT's substs.
-                                .with_self_ty(cx.tcx, cx.tcx.types.self_param)
-                                .projection_ty,
-                            cx,
-                        ),
-                        kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) },
-                    });
-                }
+            let mut bindings = vec![];
+            for pb in obj.projection_bounds() {
+                bindings.push(TypeBinding {
+                    assoc: projection_to_path_segment(
+                        pb.skip_binder()
+                            .lift_to_tcx(cx.tcx)
+                            .unwrap()
+                            // HACK(compiler-errors): Doesn't actually matter what self
+                            // type we put here, because we're only using the GAT's substs.
+                            .with_self_ty(cx.tcx, cx.tcx.types.self_param)
+                            .projection_ty,
+                        cx,
+                    ),
+                    kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) },
+                });
+            }
 
-                let path = external_path(cx, did, false, bindings, substs);
-                bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
+            let path = external_path(cx, did, false, bindings, substs);
+            bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
 
-                DynTrait(bounds, lifetime)
-            }
-            ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()),
+            DynTrait(bounds, lifetime)
+        }
+        ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()),
 
-            ty::Projection(ref data) => data.clean(cx),
+        ty::Projection(ref data) => clean_projection(*data, cx, def_id),
 
-            ty::Param(ref p) => {
-                if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
-                    ImplTrait(bounds)
-                } else {
-                    Generic(p.name)
-                }
+        ty::Param(ref p) => {
+            if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
+                ImplTrait(bounds)
+            } else {
+                Generic(p.name)
             }
+        }
 
-            ty::Opaque(def_id, substs) => {
-                // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
-                // by looking up the bounds associated with the def_id.
-                let substs = cx.tcx.lift(substs).expect("Opaque lift failed");
-                let bounds = cx
-                    .tcx
-                    .explicit_item_bounds(def_id)
-                    .iter()
-                    .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
-                    .collect::<Vec<_>>();
-                let mut regions = vec![];
-                let mut has_sized = false;
-                let mut bounds = bounds
-                    .iter()
-                    .filter_map(|bound| {
-                        let bound_predicate = bound.kind();
-                        let trait_ref = match bound_predicate.skip_binder() {
-                            ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
-                            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
-                                if let Some(r) = reg.clean(cx) {
-                                    regions.push(GenericBound::Outlives(r));
-                                }
-                                return None;
+        ty::Opaque(def_id, substs) => {
+            // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+            // by looking up the bounds associated with the def_id.
+            let substs = cx.tcx.lift(substs).expect("Opaque lift failed");
+            let bounds = cx
+                .tcx
+                .explicit_item_bounds(def_id)
+                .iter()
+                .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
+                .collect::<Vec<_>>();
+            let mut regions = vec![];
+            let mut has_sized = false;
+            let mut bounds = bounds
+                .iter()
+                .filter_map(|bound| {
+                    let bound_predicate = bound.kind();
+                    let trait_ref = match bound_predicate.skip_binder() {
+                        ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
+                        ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
+                            if let Some(r) = reg.clean(cx) {
+                                regions.push(GenericBound::Outlives(r));
                             }
-                            _ => return None,
-                        };
+                            return None;
+                        }
+                        _ => return None,
+                    };
 
-                        if let Some(sized) = cx.tcx.lang_items().sized_trait() {
-                            if trait_ref.def_id() == sized {
-                                has_sized = true;
-                                return None;
-                            }
+                    if let Some(sized) = cx.tcx.lang_items().sized_trait() {
+                        if trait_ref.def_id() == sized {
+                            has_sized = true;
+                            return None;
                         }
+                    }
 
-                        let bindings: Vec<_> = bounds
-                            .iter()
-                            .filter_map(|bound| {
-                                if let ty::PredicateKind::Projection(proj) =
-                                    bound.kind().skip_binder()
-                                {
-                                    if proj.projection_ty.trait_ref(cx.tcx)
-                                        == trait_ref.skip_binder()
-                                    {
-                                        Some(TypeBinding {
-                                            assoc: projection_to_path_segment(
-                                                proj.projection_ty,
-                                                cx,
-                                            ),
-                                            kind: TypeBindingKind::Equality {
-                                                term: proj.term.clean(cx),
-                                            },
-                                        })
-                                    } else {
-                                        None
-                                    }
+                    let bindings: Vec<_> = bounds
+                        .iter()
+                        .filter_map(|bound| {
+                            if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
+                            {
+                                if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
+                                    Some(TypeBinding {
+                                        assoc: projection_to_path_segment(proj.projection_ty, cx),
+                                        kind: TypeBindingKind::Equality {
+                                            term: proj.term.clean(cx),
+                                        },
+                                    })
                                 } else {
                                     None
                                 }
-                            })
-                            .collect();
+                            } else {
+                                None
+                            }
+                        })
+                        .collect();
 
-                        Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
-                    })
-                    .collect::<Vec<_>>();
-                bounds.extend(regions);
-                if !has_sized && !bounds.is_empty() {
-                    bounds.insert(0, GenericBound::maybe_sized(cx));
-                }
-                ImplTrait(bounds)
+                    Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
+                })
+                .collect::<Vec<_>>();
+            bounds.extend(regions);
+            if !has_sized && !bounds.is_empty() {
+                bounds.insert(0, GenericBound::maybe_sized(cx));
             }
+            ImplTrait(bounds)
+        }
 
-            ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
+        ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
 
-            ty::Bound(..) => panic!("Bound"),
-            ty::Placeholder(..) => panic!("Placeholder"),
-            ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
-            ty::Infer(..) => panic!("Infer"),
-            ty::Error(_) => panic!("Error"),
-        }
+        ty::Bound(..) => panic!("Bound"),
+        ty::Placeholder(..) => panic!("Placeholder"),
+        ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
+        ty::Infer(..) => panic!("Infer"),
+        ty::Error(_) => panic!("Error"),
+    }
+}
+
+impl<'tcx> Clean<Type> for Ty<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Type {
+        clean_ty(*self, cx, None)
     }
 }