Skip to content

Commit 95bf127

Browse files
committed
Support middle::ty assoc const eq predicates again
1 parent 911d4a0 commit 95bf127

File tree

6 files changed

+92
-119
lines changed

6 files changed

+92
-119
lines changed

src/librustdoc/clean/mod.rs

Lines changed: 50 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -371,10 +371,9 @@ fn clean_where_predicate<'tcx>(
371371
bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
372372
},
373373

374-
hir::WherePredicateKind::EqPredicate(wrp) => WherePredicate::EqPredicate {
375-
lhs: clean_ty(wrp.lhs_ty, cx),
376-
rhs: clean_ty(wrp.rhs_ty, cx).into(),
377-
},
374+
// We should never actually reach this case because these predicates should've already been
375+
// rejected in an earlier compiler pass. This feature isn't fully implemented (#20041).
376+
hir::WherePredicateKind::EqPredicate(_) => bug!("EqPredicate"),
378377
})
379378
}
380379

@@ -470,46 +469,34 @@ fn clean_projection_predicate<'tcx>(
470469
cx: &mut DocContext<'tcx>,
471470
) -> WherePredicate {
472471
WherePredicate::EqPredicate {
473-
lhs: clean_projection(
474-
pred.map_bound(|p| {
475-
// FIXME: This needs to be made resilient for `AliasTerm`s that
476-
// are associated consts.
477-
p.projection_term.expect_ty(cx.tcx)
478-
}),
479-
cx,
480-
None,
481-
),
472+
lhs: clean_projection(pred.map_bound(|p| p.projection_term), cx, None),
482473
rhs: clean_middle_term(pred.map_bound(|p| p.term), cx),
483474
}
484475
}
485476

486477
fn clean_projection<'tcx>(
487-
ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
478+
proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>,
488479
cx: &mut DocContext<'tcx>,
489-
def_id: Option<DefId>,
490-
) -> Type {
491-
if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) {
492-
return clean_middle_opaque_bounds(cx, ty.skip_binder().def_id, ty.skip_binder().args);
493-
}
494-
480+
parent_def_id: Option<DefId>,
481+
) -> QPathData {
495482
let trait_ = clean_trait_ref_with_constraints(
496483
cx,
497-
ty.map_bound(|ty| ty.trait_ref(cx.tcx)),
484+
proj.map_bound(|proj| proj.trait_ref(cx.tcx)),
498485
ThinVec::new(),
499486
);
500-
let self_type = clean_middle_ty(ty.map_bound(|ty| ty.self_ty()), cx, None, None);
501-
let self_def_id = if let Some(def_id) = def_id {
502-
cx.tcx.opt_parent(def_id).or(Some(def_id))
503-
} else {
504-
self_type.def_id(&cx.cache)
487+
let self_type = clean_middle_ty(proj.map_bound(|proj| proj.self_ty()), cx, None, None);
488+
let self_def_id = match parent_def_id {
489+
Some(parent_def_id) => cx.tcx.opt_parent(parent_def_id).or(Some(parent_def_id)),
490+
None => self_type.def_id(&cx.cache),
505491
};
506492
let should_fully_qualify = should_fully_qualify_path(self_def_id, &trait_, &self_type);
507-
Type::QPath(Box::new(QPathData {
508-
assoc: projection_to_path_segment(ty, cx),
509-
should_fully_qualify,
493+
494+
QPathData {
495+
assoc: projection_to_path_segment(proj, cx),
510496
self_type,
497+
should_fully_qualify,
511498
trait_: Some(trait_),
512-
}))
499+
}
513500
}
514501

515502
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
520507
}
521508

522509
fn projection_to_path_segment<'tcx>(
523-
ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
510+
proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>,
524511
cx: &mut DocContext<'tcx>,
525512
) -> PathSegment {
526-
let def_id = ty.skip_binder().def_id;
527-
let item = cx.tcx.associated_item(def_id);
513+
let def_id = proj.skip_binder().def_id;
528514
let generics = cx.tcx.generics_of(def_id);
529515
PathSegment {
530-
name: item.name(),
516+
name: cx.tcx.item_name(def_id),
531517
args: GenericArgs::AngleBracketed {
532518
args: clean_middle_generic_args(
533519
cx,
534-
ty.map_bound(|ty| &ty.args[generics.parent_count..]),
520+
proj.map_bound(|ty| &ty.args[generics.parent_count..]),
535521
false,
536522
def_id,
537523
),
@@ -845,7 +831,7 @@ fn clean_ty_generics<'tcx>(
845831
.predicates
846832
.iter()
847833
.flat_map(|(pred, _)| {
848-
let mut projection = None;
834+
let mut proj_pred = None;
849835
let param_idx = {
850836
let bound_p = pred.kind();
851837
match bound_p.skip_binder() {
@@ -860,7 +846,7 @@ fn clean_ty_generics<'tcx>(
860846
ty::ClauseKind::Projection(p)
861847
if let ty::Param(param) = p.projection_term.self_ty().kind() =>
862848
{
863-
projection = Some(bound_p.rebind(p));
849+
proj_pred = Some(bound_p.rebind(p));
864850
Some(param.index)
865851
}
866852
_ => None,
@@ -874,22 +860,12 @@ fn clean_ty_generics<'tcx>(
874860

875861
bounds.extend(pred.get_bounds().into_iter().flatten().cloned());
876862

877-
if let Some(proj) = projection
878-
&& let lhs = clean_projection(
879-
proj.map_bound(|p| {
880-
// FIXME: This needs to be made resilient for `AliasTerm`s that
881-
// are associated consts.
882-
p.projection_term.expect_ty(cx.tcx)
883-
}),
884-
cx,
885-
None,
886-
)
887-
&& let Some((_, trait_did, name)) = lhs.projection()
888-
{
863+
if let Some(pred) = proj_pred {
864+
let lhs = clean_projection(pred.map_bound(|p| p.projection_term), cx, None);
889865
impl_trait_proj.entry(param_idx).or_default().push((
890-
trait_did,
891-
name,
892-
proj.map_bound(|p| p.term),
866+
lhs.trait_.unwrap().def_id(),
867+
lhs.assoc,
868+
pred.map_bound(|p| p.term),
893869
));
894870
}
895871

@@ -2146,14 +2122,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
21462122
.map(|pb| AssocItemConstraint {
21472123
assoc: projection_to_path_segment(
21482124
pb.map_bound(|pb| {
2149-
pb
2150-
// HACK(compiler-errors): Doesn't actually matter what self
2151-
// type we put here, because we're only using the GAT's args.
2152-
.with_self_ty(cx.tcx, cx.tcx.types.self_param)
2125+
pb.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self)
21532126
.projection_term
2154-
// FIXME: This needs to be made resilient for `AliasTerm`s
2155-
// that are associated consts.
2156-
.expect_ty(cx.tcx)
21572127
}),
21582128
cx,
21592129
),
@@ -2186,18 +2156,25 @@ pub(crate) fn clean_middle_ty<'tcx>(
21862156
Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect())
21872157
}
21882158

2189-
ty::Alias(ty::Projection, data) => {
2190-
clean_projection(bound_ty.rebind(data), cx, parent_def_id)
2159+
ty::Alias(ty::Projection, alias_ty @ ty::AliasTy { def_id, args, .. }) => {
2160+
if cx.tcx.is_impl_trait_in_trait(def_id) {
2161+
clean_middle_opaque_bounds(cx, def_id, args)
2162+
} else {
2163+
Type::QPath(Box::new(clean_projection(
2164+
bound_ty.rebind(alias_ty.into()),
2165+
cx,
2166+
parent_def_id,
2167+
)))
2168+
}
21912169
}
21922170

2193-
ty::Alias(ty::Inherent, alias_ty) => {
2194-
let def_id = alias_ty.def_id;
2171+
ty::Alias(ty::Inherent, alias_ty @ ty::AliasTy { def_id, .. }) => {
21952172
let alias_ty = bound_ty.rebind(alias_ty);
21962173
let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None, None);
21972174

21982175
Type::QPath(Box::new(QPathData {
21992176
assoc: PathSegment {
2200-
name: cx.tcx.associated_item(def_id).name(),
2177+
name: cx.tcx.item_name(def_id),
22012178
args: GenericArgs::AngleBracketed {
22022179
args: clean_middle_generic_args(
22032180
cx,
@@ -2214,20 +2191,15 @@ pub(crate) fn clean_middle_ty<'tcx>(
22142191
}))
22152192
}
22162193

2217-
ty::Alias(ty::Free, data) => {
2194+
ty::Alias(ty::Free, ty::AliasTy { def_id, args, .. }) => {
22182195
if cx.tcx.features().lazy_type_alias() {
22192196
// Free type alias `data` represents the `type X` in `type X = Y`. If we need `Y`,
22202197
// we need to use `type_of`.
2221-
let path = clean_middle_path(
2222-
cx,
2223-
data.def_id,
2224-
false,
2225-
ThinVec::new(),
2226-
bound_ty.rebind(data.args),
2227-
);
2198+
let path =
2199+
clean_middle_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args));
22282200
Type::Path { path }
22292201
} else {
2230-
let ty = cx.tcx.type_of(data.def_id).instantiate(cx.tcx, data.args);
2202+
let ty = cx.tcx.type_of(def_id).instantiate(cx.tcx, args);
22312203
clean_middle_ty(bound_ty.rebind(ty), cx, None, None)
22322204
}
22332205
}
@@ -2314,18 +2286,17 @@ fn clean_middle_opaque_bounds<'tcx>(
23142286
let bindings: ThinVec<_> = bounds
23152287
.iter()
23162288
.filter_map(|(bound, _)| {
2317-
if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder()
2318-
&& proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder()
2289+
let bound = bound.kind();
2290+
if let ty::ClauseKind::Projection(proj_pred) = bound.skip_binder()
2291+
&& proj_pred.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder()
23192292
{
23202293
return Some(AssocItemConstraint {
23212294
assoc: projection_to_path_segment(
2322-
// FIXME: This needs to be made resilient for `AliasTerm`s that
2323-
// are associated consts.
2324-
bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)),
2295+
bound.rebind(proj_pred.projection_term),
23252296
cx,
23262297
),
23272298
kind: AssocItemConstraintKind::Equality {
2328-
term: clean_middle_term(bound.kind().rebind(proj.term), cx),
2299+
term: clean_middle_term(bound.rebind(proj_pred.term), cx),
23292300
},
23302301
});
23312302
}

src/librustdoc/clean/simplify.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,8 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: ThinVec<WP>) -> ThinVe
4646
// Look for equality predicates on associated types that can be merged into
4747
// general bound predicates.
4848
equalities.retain(|(lhs, rhs)| {
49-
let Some((ty, trait_did, name)) = lhs.projection() else {
50-
return true;
51-
};
52-
let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
53-
merge_bounds(cx, bounds, trait_did, name, rhs)
49+
let Some((bounds, _)) = tybounds.get_mut(&lhs.self_type) else { return true };
50+
merge_bounds(cx, bounds, lhs.trait_.as_ref().unwrap().def_id(), lhs.assoc.clone(), rhs)
5451
});
5552

5653
// And finally, let's reassemble everything

src/librustdoc/clean/types.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,7 +1341,7 @@ impl PreciseCapturingArg {
13411341
pub(crate) enum WherePredicate {
13421342
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
13431343
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1344-
EqPredicate { lhs: Type, rhs: Term },
1344+
EqPredicate { lhs: QPathData, rhs: Term },
13451345
}
13461346

13471347
impl WherePredicate {
@@ -1704,14 +1704,6 @@ impl Type {
17041704
matches!(self, Type::Tuple(v) if v.is_empty())
17051705
}
17061706

1707-
pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
1708-
if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self {
1709-
Some((self_type, trait_.as_ref()?.def_id(), assoc.clone()))
1710-
} else {
1711-
None
1712-
}
1713-
}
1714-
17151707
/// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
17161708
///
17171709
/// [clean]: crate::clean

src/librustdoc/html/format.rs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,12 +1019,27 @@ fn fmt_type(
10191019
f.write_str("impl ")?;
10201020
print_generic_bounds(bounds, cx).fmt(f)
10211021
}
1022-
&clean::QPath(box clean::QPathData {
1023-
ref assoc,
1024-
ref self_type,
1025-
ref trait_,
1026-
should_fully_qualify,
1027-
}) => {
1022+
clean::QPath(qpath) => qpath.print(cx).fmt(f),
1023+
}
1024+
}
1025+
1026+
impl clean::Type {
1027+
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
1028+
fmt::from_fn(move |f| fmt_type(self, f, false, cx))
1029+
}
1030+
}
1031+
1032+
impl clean::Path {
1033+
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
1034+
fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
1035+
}
1036+
}
1037+
1038+
impl clean::QPathData {
1039+
fn print(&self, cx: &Context<'_>) -> impl Display {
1040+
let Self { ref assoc, ref self_type, should_fully_qualify, ref trait_ } = *self;
1041+
1042+
fmt::from_fn(move |f| {
10281043
// FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719),
10291044
// we need to surround them with angle brackets in some cases (e.g. `<dyn …>::P`).
10301045

@@ -1090,19 +1105,7 @@ fn fmt_type(
10901105
}?;
10911106

10921107
assoc.args.print(cx).fmt(f)
1093-
}
1094-
}
1095-
}
1096-
1097-
impl clean::Type {
1098-
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
1099-
fmt::from_fn(move |f| fmt_type(self, f, false, cx))
1100-
}
1101-
}
1102-
1103-
impl clean::Path {
1104-
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
1105-
fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
1108+
})
11061109
}
11071110
}
11081111

src/librustdoc/json/conversions.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,9 @@ impl FromClean<clean::WherePredicate> for WherePredicate {
468468
.collect(),
469469
},
470470
EqPredicate { lhs, rhs } => WherePredicate::EqPredicate {
471+
// The LHS currently has type `Type` but it should be a `QualifiedPath` since it may
472+
// refer to an associated const. However, `EqPredicate` shouldn't exist in the first
473+
// place: <https://github.com/rust-lang/rust/141368>.
471474
lhs: lhs.into_json(renderer),
472475
rhs: rhs.into_json(renderer),
473476
},
@@ -557,12 +560,7 @@ impl FromClean<clean::Type> for Type {
557560
is_mutable: mutability == ast::Mutability::Mut,
558561
type_: Box::new((*type_).into_json(renderer)),
559562
},
560-
QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath {
561-
name: assoc.name.to_string(),
562-
args: Box::new(assoc.args.into_json(renderer)),
563-
self_type: Box::new(self_type.into_json(renderer)),
564-
trait_: trait_.map(|trait_| trait_.into_json(renderer)),
565-
},
563+
QPath(qpath) => (*qpath).into_json(renderer),
566564
// FIXME(unsafe_binder): Implement rustdoc-json.
567565
UnsafeBinder(_) => todo!(),
568566
}
@@ -579,6 +577,19 @@ impl FromClean<clean::Path> for Path {
579577
}
580578
}
581579

580+
impl FromClean<clean::QPathData> for Type {
581+
fn from_clean(qpath: clean::QPathData, renderer: &JsonRenderer<'_>) -> Self {
582+
let clean::QPathData { assoc, self_type, should_fully_qualify: _, trait_ } = qpath;
583+
584+
Self::QualifiedPath {
585+
name: assoc.name.to_string(),
586+
args: Box::new(assoc.args.into_json(renderer)),
587+
self_type: Box::new(self_type.into_json(renderer)),
588+
trait_: trait_.map(|trait_| trait_.into_json(renderer)),
589+
}
590+
}
591+
}
592+
582593
impl FromClean<clean::Term> for Term {
583594
fn from_clean(term: clean::Term, renderer: &JsonRenderer<'_>) -> Term {
584595
match term {

tests/rustdoc/inline_cross/assoc-const-equality.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//@ aux-crate:assoc_const_equality=assoc-const-equality.rs
22
//@ edition:2021
3-
//@ ignore-test (FIXME: #125092)
43

54
#![crate_name = "user"]
65

0 commit comments

Comments
 (0)