Support middle::ty assoc const eq predicates again
This commit is contained in:
parent
911d4a0c06
commit
95bf1275f5
6 changed files with 92 additions and 119 deletions
|
|
@ -371,10 +371,9 @@ fn clean_where_predicate<'tcx>(
|
|||
bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
|
||||
},
|
||||
|
||||
hir::WherePredicateKind::EqPredicate(wrp) => WherePredicate::EqPredicate {
|
||||
lhs: clean_ty(wrp.lhs_ty, cx),
|
||||
rhs: clean_ty(wrp.rhs_ty, cx).into(),
|
||||
},
|
||||
// We should never actually reach this case because these predicates should've already been
|
||||
// rejected in an earlier compiler pass. This feature isn't fully implemented (#20041).
|
||||
hir::WherePredicateKind::EqPredicate(_) => bug!("EqPredicate"),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -470,46 +469,34 @@ fn clean_projection_predicate<'tcx>(
|
|||
cx: &mut DocContext<'tcx>,
|
||||
) -> WherePredicate {
|
||||
WherePredicate::EqPredicate {
|
||||
lhs: clean_projection(
|
||||
pred.map_bound(|p| {
|
||||
// FIXME: This needs to be made resilient for `AliasTerm`s that
|
||||
// are associated consts.
|
||||
p.projection_term.expect_ty(cx.tcx)
|
||||
}),
|
||||
cx,
|
||||
None,
|
||||
),
|
||||
lhs: clean_projection(pred.map_bound(|p| p.projection_term), cx, None),
|
||||
rhs: clean_middle_term(pred.map_bound(|p| p.term), cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_projection<'tcx>(
|
||||
ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
|
||||
proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
def_id: Option<DefId>,
|
||||
) -> Type {
|
||||
if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) {
|
||||
return clean_middle_opaque_bounds(cx, ty.skip_binder().def_id, ty.skip_binder().args);
|
||||
}
|
||||
|
||||
parent_def_id: Option<DefId>,
|
||||
) -> QPathData {
|
||||
let trait_ = clean_trait_ref_with_constraints(
|
||||
cx,
|
||||
ty.map_bound(|ty| ty.trait_ref(cx.tcx)),
|
||||
proj.map_bound(|proj| proj.trait_ref(cx.tcx)),
|
||||
ThinVec::new(),
|
||||
);
|
||||
let self_type = clean_middle_ty(ty.map_bound(|ty| ty.self_ty()), cx, None, None);
|
||||
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 self_type = clean_middle_ty(proj.map_bound(|proj| proj.self_ty()), cx, None, None);
|
||||
let self_def_id = match parent_def_id {
|
||||
Some(parent_def_id) => cx.tcx.opt_parent(parent_def_id).or(Some(parent_def_id)),
|
||||
None => self_type.def_id(&cx.cache),
|
||||
};
|
||||
let should_fully_qualify = should_fully_qualify_path(self_def_id, &trait_, &self_type);
|
||||
Type::QPath(Box::new(QPathData {
|
||||
assoc: projection_to_path_segment(ty, cx),
|
||||
should_fully_qualify,
|
||||
|
||||
QPathData {
|
||||
assoc: projection_to_path_segment(proj, cx),
|
||||
self_type,
|
||||
should_fully_qualify,
|
||||
trait_: Some(trait_),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
fn should_fully_qualify_path(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
|
||||
|
|
@ -520,18 +507,17 @@ fn should_fully_qualify_path(self_def_id: Option<DefId>, trait_: &Path, self_typ
|
|||
}
|
||||
|
||||
fn projection_to_path_segment<'tcx>(
|
||||
ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
|
||||
proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
) -> PathSegment {
|
||||
let def_id = ty.skip_binder().def_id;
|
||||
let item = cx.tcx.associated_item(def_id);
|
||||
let def_id = proj.skip_binder().def_id;
|
||||
let generics = cx.tcx.generics_of(def_id);
|
||||
PathSegment {
|
||||
name: item.name(),
|
||||
name: cx.tcx.item_name(def_id),
|
||||
args: GenericArgs::AngleBracketed {
|
||||
args: clean_middle_generic_args(
|
||||
cx,
|
||||
ty.map_bound(|ty| &ty.args[generics.parent_count..]),
|
||||
proj.map_bound(|ty| &ty.args[generics.parent_count..]),
|
||||
false,
|
||||
def_id,
|
||||
),
|
||||
|
|
@ -845,7 +831,7 @@ fn clean_ty_generics<'tcx>(
|
|||
.predicates
|
||||
.iter()
|
||||
.flat_map(|(pred, _)| {
|
||||
let mut projection = None;
|
||||
let mut proj_pred = None;
|
||||
let param_idx = {
|
||||
let bound_p = pred.kind();
|
||||
match bound_p.skip_binder() {
|
||||
|
|
@ -860,7 +846,7 @@ fn clean_ty_generics<'tcx>(
|
|||
ty::ClauseKind::Projection(p)
|
||||
if let ty::Param(param) = p.projection_term.self_ty().kind() =>
|
||||
{
|
||||
projection = Some(bound_p.rebind(p));
|
||||
proj_pred = Some(bound_p.rebind(p));
|
||||
Some(param.index)
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -874,22 +860,12 @@ fn clean_ty_generics<'tcx>(
|
|||
|
||||
bounds.extend(pred.get_bounds().into_iter().flatten().cloned());
|
||||
|
||||
if let Some(proj) = projection
|
||||
&& let lhs = clean_projection(
|
||||
proj.map_bound(|p| {
|
||||
// FIXME: This needs to be made resilient for `AliasTerm`s that
|
||||
// are associated consts.
|
||||
p.projection_term.expect_ty(cx.tcx)
|
||||
}),
|
||||
cx,
|
||||
None,
|
||||
)
|
||||
&& let Some((_, trait_did, name)) = lhs.projection()
|
||||
{
|
||||
if let Some(pred) = proj_pred {
|
||||
let lhs = clean_projection(pred.map_bound(|p| p.projection_term), cx, None);
|
||||
impl_trait_proj.entry(param_idx).or_default().push((
|
||||
trait_did,
|
||||
name,
|
||||
proj.map_bound(|p| p.term),
|
||||
lhs.trait_.unwrap().def_id(),
|
||||
lhs.assoc,
|
||||
pred.map_bound(|p| p.term),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -2146,14 +2122,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||
.map(|pb| AssocItemConstraint {
|
||||
assoc: projection_to_path_segment(
|
||||
pb.map_bound(|pb| {
|
||||
pb
|
||||
// HACK(compiler-errors): Doesn't actually matter what self
|
||||
// type we put here, because we're only using the GAT's args.
|
||||
.with_self_ty(cx.tcx, cx.tcx.types.self_param)
|
||||
pb.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self)
|
||||
.projection_term
|
||||
// FIXME: This needs to be made resilient for `AliasTerm`s
|
||||
// that are associated consts.
|
||||
.expect_ty(cx.tcx)
|
||||
}),
|
||||
cx,
|
||||
),
|
||||
|
|
@ -2186,18 +2156,25 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||
Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect())
|
||||
}
|
||||
|
||||
ty::Alias(ty::Projection, data) => {
|
||||
clean_projection(bound_ty.rebind(data), cx, parent_def_id)
|
||||
ty::Alias(ty::Projection, alias_ty @ ty::AliasTy { def_id, args, .. }) => {
|
||||
if cx.tcx.is_impl_trait_in_trait(def_id) {
|
||||
clean_middle_opaque_bounds(cx, def_id, args)
|
||||
} else {
|
||||
Type::QPath(Box::new(clean_projection(
|
||||
bound_ty.rebind(alias_ty.into()),
|
||||
cx,
|
||||
parent_def_id,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
ty::Alias(ty::Inherent, alias_ty) => {
|
||||
let def_id = alias_ty.def_id;
|
||||
ty::Alias(ty::Inherent, alias_ty @ ty::AliasTy { def_id, .. }) => {
|
||||
let alias_ty = bound_ty.rebind(alias_ty);
|
||||
let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None, None);
|
||||
|
||||
Type::QPath(Box::new(QPathData {
|
||||
assoc: PathSegment {
|
||||
name: cx.tcx.associated_item(def_id).name(),
|
||||
name: cx.tcx.item_name(def_id),
|
||||
args: GenericArgs::AngleBracketed {
|
||||
args: clean_middle_generic_args(
|
||||
cx,
|
||||
|
|
@ -2214,20 +2191,15 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||
}))
|
||||
}
|
||||
|
||||
ty::Alias(ty::Free, data) => {
|
||||
ty::Alias(ty::Free, ty::AliasTy { def_id, args, .. }) => {
|
||||
if cx.tcx.features().lazy_type_alias() {
|
||||
// Free type alias `data` represents the `type X` in `type X = Y`. If we need `Y`,
|
||||
// we need to use `type_of`.
|
||||
let path = clean_middle_path(
|
||||
cx,
|
||||
data.def_id,
|
||||
false,
|
||||
ThinVec::new(),
|
||||
bound_ty.rebind(data.args),
|
||||
);
|
||||
let path =
|
||||
clean_middle_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args));
|
||||
Type::Path { path }
|
||||
} else {
|
||||
let ty = cx.tcx.type_of(data.def_id).instantiate(cx.tcx, data.args);
|
||||
let ty = cx.tcx.type_of(def_id).instantiate(cx.tcx, args);
|
||||
clean_middle_ty(bound_ty.rebind(ty), cx, None, None)
|
||||
}
|
||||
}
|
||||
|
|
@ -2314,18 +2286,17 @@ fn clean_middle_opaque_bounds<'tcx>(
|
|||
let bindings: ThinVec<_> = bounds
|
||||
.iter()
|
||||
.filter_map(|(bound, _)| {
|
||||
if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder()
|
||||
&& proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder()
|
||||
let bound = bound.kind();
|
||||
if let ty::ClauseKind::Projection(proj_pred) = bound.skip_binder()
|
||||
&& proj_pred.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder()
|
||||
{
|
||||
return Some(AssocItemConstraint {
|
||||
assoc: projection_to_path_segment(
|
||||
// FIXME: This needs to be made resilient for `AliasTerm`s that
|
||||
// are associated consts.
|
||||
bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)),
|
||||
bound.rebind(proj_pred.projection_term),
|
||||
cx,
|
||||
),
|
||||
kind: AssocItemConstraintKind::Equality {
|
||||
term: clean_middle_term(bound.kind().rebind(proj.term), cx),
|
||||
term: clean_middle_term(bound.rebind(proj_pred.term), cx),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,11 +46,8 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: ThinVec<WP>) -> ThinVe
|
|||
// Look for equality predicates on associated types that can be merged into
|
||||
// general bound predicates.
|
||||
equalities.retain(|(lhs, rhs)| {
|
||||
let Some((ty, trait_did, name)) = lhs.projection() else {
|
||||
return true;
|
||||
};
|
||||
let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
|
||||
merge_bounds(cx, bounds, trait_did, name, rhs)
|
||||
let Some((bounds, _)) = tybounds.get_mut(&lhs.self_type) else { return true };
|
||||
merge_bounds(cx, bounds, lhs.trait_.as_ref().unwrap().def_id(), lhs.assoc.clone(), rhs)
|
||||
});
|
||||
|
||||
// And finally, let's reassemble everything
|
||||
|
|
|
|||
|
|
@ -1341,7 +1341,7 @@ impl PreciseCapturingArg {
|
|||
pub(crate) enum WherePredicate {
|
||||
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
|
||||
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
|
||||
EqPredicate { lhs: Type, rhs: Term },
|
||||
EqPredicate { lhs: QPathData, rhs: Term },
|
||||
}
|
||||
|
||||
impl WherePredicate {
|
||||
|
|
@ -1704,14 +1704,6 @@ impl Type {
|
|||
matches!(self, Type::Tuple(v) if v.is_empty())
|
||||
}
|
||||
|
||||
pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
|
||||
if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self {
|
||||
Some((self_type, trait_.as_ref()?.def_id(), assoc.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
|
||||
///
|
||||
/// [clean]: crate::clean
|
||||
|
|
|
|||
|
|
@ -1019,12 +1019,27 @@ fn fmt_type(
|
|||
f.write_str("impl ")?;
|
||||
print_generic_bounds(bounds, cx).fmt(f)
|
||||
}
|
||||
&clean::QPath(box clean::QPathData {
|
||||
ref assoc,
|
||||
ref self_type,
|
||||
ref trait_,
|
||||
should_fully_qualify,
|
||||
}) => {
|
||||
clean::QPath(qpath) => qpath.print(cx).fmt(f),
|
||||
}
|
||||
}
|
||||
|
||||
impl clean::Type {
|
||||
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
|
||||
fmt::from_fn(move |f| fmt_type(self, f, false, cx))
|
||||
}
|
||||
}
|
||||
|
||||
impl clean::Path {
|
||||
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
|
||||
fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
|
||||
}
|
||||
}
|
||||
|
||||
impl clean::QPathData {
|
||||
fn print(&self, cx: &Context<'_>) -> impl Display {
|
||||
let Self { ref assoc, ref self_type, should_fully_qualify, ref trait_ } = *self;
|
||||
|
||||
fmt::from_fn(move |f| {
|
||||
// FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719),
|
||||
// we need to surround them with angle brackets in some cases (e.g. `<dyn …>::P`).
|
||||
|
||||
|
|
@ -1090,19 +1105,7 @@ fn fmt_type(
|
|||
}?;
|
||||
|
||||
assoc.args.print(cx).fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl clean::Type {
|
||||
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
|
||||
fmt::from_fn(move |f| fmt_type(self, f, false, cx))
|
||||
}
|
||||
}
|
||||
|
||||
impl clean::Path {
|
||||
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
|
||||
fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -468,6 +468,9 @@ impl FromClean<clean::WherePredicate> for WherePredicate {
|
|||
.collect(),
|
||||
},
|
||||
EqPredicate { lhs, rhs } => WherePredicate::EqPredicate {
|
||||
// The LHS currently has type `Type` but it should be a `QualifiedPath` since it may
|
||||
// refer to an associated const. However, `EqPredicate` shouldn't exist in the first
|
||||
// place: <https://github.com/rust-lang/rust/141368>.
|
||||
lhs: lhs.into_json(renderer),
|
||||
rhs: rhs.into_json(renderer),
|
||||
},
|
||||
|
|
@ -557,12 +560,7 @@ impl FromClean<clean::Type> for Type {
|
|||
is_mutable: mutability == ast::Mutability::Mut,
|
||||
type_: Box::new((*type_).into_json(renderer)),
|
||||
},
|
||||
QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath {
|
||||
name: assoc.name.to_string(),
|
||||
args: Box::new(assoc.args.into_json(renderer)),
|
||||
self_type: Box::new(self_type.into_json(renderer)),
|
||||
trait_: trait_.map(|trait_| trait_.into_json(renderer)),
|
||||
},
|
||||
QPath(qpath) => (*qpath).into_json(renderer),
|
||||
// FIXME(unsafe_binder): Implement rustdoc-json.
|
||||
UnsafeBinder(_) => todo!(),
|
||||
}
|
||||
|
|
@ -579,6 +577,19 @@ impl FromClean<clean::Path> for Path {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromClean<clean::QPathData> for Type {
|
||||
fn from_clean(qpath: clean::QPathData, renderer: &JsonRenderer<'_>) -> Self {
|
||||
let clean::QPathData { assoc, self_type, should_fully_qualify: _, trait_ } = qpath;
|
||||
|
||||
Self::QualifiedPath {
|
||||
name: assoc.name.to_string(),
|
||||
args: Box::new(assoc.args.into_json(renderer)),
|
||||
self_type: Box::new(self_type.into_json(renderer)),
|
||||
trait_: trait_.map(|trait_| trait_.into_json(renderer)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromClean<clean::Term> for Term {
|
||||
fn from_clean(term: clean::Term, renderer: &JsonRenderer<'_>) -> Term {
|
||||
match term {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//@ aux-crate:assoc_const_equality=assoc-const-equality.rs
|
||||
//@ edition:2021
|
||||
//@ ignore-test (FIXME: #125092)
|
||||
|
||||
#![crate_name = "user"]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue