Prevent to recompute should_show_cast by passing down self_def_id

This commit is contained in:
Guillaume Gomez 2022-04-26 16:40:42 +02:00
parent 4054c0f3e6
commit 2e1369c198

View File

@ -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> { impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> Type { fn clean(&self, cx: &mut DocContext<'_>) -> Type {
let lifted = self.lift_to_tcx(cx.tcx).unwrap(); clean_projection(*self, cx, None)
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_,
}
} }
} }
@ -422,23 +434,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
} }
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
let default = if has_default { let default = if has_default {
let mut default = cx.tcx.type_of(self.def_id).clean(cx); Some(clean_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id)))
// 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)
} else { } else {
None 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_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'_>, def_id: Option<DefId>) -> Type {
fn clean(&self, cx: &mut DocContext<'_>) -> Type { trace!("cleaning type: {:?}", this);
trace!("cleaning type: {:?}", self); let ty = normalize(cx, this).unwrap_or(this);
let ty = normalize(cx, *self).unwrap_or(*self); match *ty.kind() {
match *ty.kind() { ty::Never => Primitive(PrimitiveType::Never),
ty::Never => Primitive(PrimitiveType::Never), ty::Bool => Primitive(PrimitiveType::Bool),
ty::Bool => Primitive(PrimitiveType::Bool), ty::Char => Primitive(PrimitiveType::Char),
ty::Char => Primitive(PrimitiveType::Char), ty::Int(int_ty) => Primitive(int_ty.into()),
ty::Int(int_ty) => Primitive(int_ty.into()), ty::Uint(uint_ty) => Primitive(uint_ty.into()),
ty::Uint(uint_ty) => Primitive(uint_ty.into()), ty::Float(float_ty) => Primitive(float_ty.into()),
ty::Float(float_ty) => Primitive(float_ty.into()), ty::Str => Primitive(PrimitiveType::Str),
ty::Str => Primitive(PrimitiveType::Str), ty::Slice(ty) => Slice(box ty.clean(cx)),
ty::Slice(ty) => Slice(box ty.clean(cx)), ty::Array(ty, n) => {
ty::Array(ty, n) => { let mut n = cx.tcx.lift(n).expect("array lift failed");
let mut n = cx.tcx.lift(n).expect("array lift failed"); n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
n = n.eval(cx.tcx, ty::ParamEnv::reveal_all()); let n = print_const(cx, n);
let n = print_const(cx, n); Array(box ty.clean(cx), n)
Array(box ty.clean(cx), n) }
} ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)),
ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)), ty::Ref(r, ty, mutbl) => {
ty::Ref(r, ty, mutbl) => { BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) }
BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) } }
} ty::FnDef(..) | ty::FnPtr(_) => {
ty::FnDef(..) | ty::FnPtr(_) => { let ty = cx.tcx.lift(this).expect("FnPtr lift failed");
let ty = cx.tcx.lift(*self).expect("FnPtr lift failed"); let sig = ty.fn_sig(cx.tcx);
let sig = ty.fn_sig(cx.tcx); let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
let decl = clean_fn_decl_from_did_and_sig(cx, None, sig); BareFunction(box BareFunctionDecl {
BareFunction(box BareFunctionDecl { unsafety: sig.unsafety(),
unsafety: sig.unsafety(), generic_params: Vec::new(),
generic_params: Vec::new(), decl,
decl, abi: sig.abi(),
abi: sig.abi(), })
}) }
} ty::Adt(def, substs) => {
ty::Adt(def, substs) => { let did = def.did();
let did = def.did(); let kind = match def.adt_kind() {
let kind = match def.adt_kind() { AdtKind::Struct => ItemType::Struct,
AdtKind::Struct => ItemType::Struct, AdtKind::Union => ItemType::Union,
AdtKind::Union => ItemType::Union, AdtKind::Enum => ItemType::Enum,
AdtKind::Enum => ItemType::Enum, };
}; inline::record_extern_fqn(cx, did, kind);
inline::record_extern_fqn(cx, did, kind); let path = external_path(cx, did, false, vec![], substs);
let path = external_path(cx, did, false, vec![], substs); Type::Path { path }
Type::Path { path } }
} ty::Foreign(did) => {
ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType);
inline::record_extern_fqn(cx, did, ItemType::ForeignType); let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
let path = external_path(cx, did, false, vec![], InternalSubsts::empty()); Type::Path { path }
Type::Path { path } }
} ty::Dynamic(obj, ref reg) => {
ty::Dynamic(obj, ref reg) => { // HACK: pick the first `did` as the `did` of the trait object. Someone
// HACK: pick the first `did` as the `did` of the trait object. Someone // might want to implement "native" support for marker-trait-only
// might want to implement "native" support for marker-trait-only // trait objects.
// trait objects. let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits()); let did = dids
let did = dids .next()
.next() .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this));
.unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", self)); let substs = match obj.principal() {
let substs = match obj.principal() { Some(principal) => principal.skip_binder().substs,
Some(principal) => principal.skip_binder().substs, // marker traits have no substs.
// marker traits have no substs. _ => cx.tcx.intern_substs(&[]),
_ => cx.tcx.intern_substs(&[]), };
};
inline::record_extern_fqn(cx, did, ItemType::Trait);
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); inline::record_extern_fqn(cx, did, ItemType::Trait);
let bound = PolyTrait { trait_: path, generic_params: Vec::new() };
let lifetime = reg.clean(cx); bounds.push(bound);
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);
}
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() });
DynTrait(bounds, lifetime)
}
ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()),
ty::Projection(ref data) => data.clean(cx),
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) => { let mut bindings = vec![];
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, for pb in obj.projection_bounds() {
// by looking up the bounds associated with the def_id. bindings.push(TypeBinding {
let substs = cx.tcx.lift(substs).expect("Opaque lift failed"); assoc: projection_to_path_segment(
let bounds = cx pb.skip_binder()
.tcx .lift_to_tcx(cx.tcx)
.explicit_item_bounds(def_id) .unwrap()
.iter() // HACK(compiler-errors): Doesn't actually matter what self
.map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs)) // type we put here, because we're only using the GAT's substs.
.collect::<Vec<_>>(); .with_self_ty(cx.tcx, cx.tcx.types.self_param)
let mut regions = vec![]; .projection_ty,
let mut has_sized = false; cx,
let mut bounds = bounds ),
.iter() kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) },
.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,
};
if let Some(sized) = cx.tcx.lang_items().sized_trait() { let path = external_path(cx, did, false, bindings, substs);
if trait_ref.def_id() == sized { bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
has_sized = true;
return None; DynTrait(bounds, lifetime)
}
ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()),
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::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,
};
let bindings: Vec<_> = bounds if let Some(sized) = cx.tcx.lang_items().sized_trait() {
.iter() if trait_ref.def_id() == sized {
.filter_map(|bound| { has_sized = true;
if let ty::PredicateKind::Projection(proj) = return None;
bound.kind().skip_binder() }
{ }
if proj.projection_ty.trait_ref(cx.tcx)
== trait_ref.skip_binder() let bindings: Vec<_> = bounds
{ .iter()
Some(TypeBinding { .filter_map(|bound| {
assoc: projection_to_path_segment( if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
proj.projection_ty, {
cx, if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
), Some(TypeBinding {
kind: TypeBindingKind::Equality { assoc: projection_to_path_segment(proj.projection_ty, cx),
term: proj.term.clean(cx), kind: TypeBindingKind::Equality {
}, term: proj.term.clean(cx),
}) },
} else { })
None
}
} else { } else {
None None
} }
}) } else {
.collect(); None
}
})
.collect();
Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings)) Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
bounds.extend(regions); bounds.extend(regions);
if !has_sized && !bounds.is_empty() { if !has_sized && !bounds.is_empty() {
bounds.insert(0, GenericBound::maybe_sized(cx)); bounds.insert(0, GenericBound::maybe_sized(cx));
}
ImplTrait(bounds)
} }
ImplTrait(bounds)
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::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"),
}
}
impl<'tcx> Clean<Type> for Ty<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> Type {
clean_ty(*self, cx, None)
} }
} }