Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,8 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe

let variances = tcx.variances_of(opaque_def_id);
let mut def_id = Some(opaque_def_id.to_def_id());
while let Some(generics) = def_id {
let generics = tcx.generics_of(generics);
while let Some(current_def_id) = def_id {
let generics = tcx.generics_of(current_def_id);
def_id = generics.parent;

for param in &generics.own_params {
Expand Down
62 changes: 52 additions & 10 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1563,17 +1563,59 @@ fn rendered_precise_capturing_args<'tcx>(
return tcx.rendered_precise_capturing_args(opaque_def_id);
}

tcx.hir_node_by_def_id(def_id).expect_opaque_ty().bounds.iter().find_map(|bound| match bound {
hir::GenericBound::Use(args, ..) => {
Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| match arg {
PreciseCapturingArgKind::Lifetime(_) => {
PreciseCapturingArgKind::Lifetime(arg.name())
let opaque = tcx.hir_node_by_def_id(def_id).expect_opaque_ty();

opaque
.bounds
.iter()
.find_map(|bound| match bound {
hir::GenericBound::Use(args, ..) => {
Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| match arg {
PreciseCapturingArgKind::Lifetime(_) => {
PreciseCapturingArgKind::Lifetime(arg.name())
}
PreciseCapturingArgKind::Param(_) => PreciseCapturingArgKind::Param(arg.name()),
})))
}
_ => None,
})
.or_else(|| {
// FIXME(fmease): Add explainer.
// FIXME(fmease): To prevent clutter, hide the synthetic use-bound if it captures all
// all in-scope early & free(!) lifetime(!) params. We know that it has
// to capture all non-lifetime params anyway due to current limitations.
// However, finding "all" uncaptured params will probably be a bit
// expensive.
if !resolve_bound_vars::opaque_captures_all_in_scope_lifetimes(opaque) {
let variances = tcx.variances_of(def_id);
let mut def_id = Some(def_id.to_def_id());
let mut captures = Vec::new();

while let Some(current_def_id) = def_id {
let generics = tcx.generics_of(current_def_id);
def_id = generics.parent;

captures.extend(generics.own_params.iter().filter_map(|param| {
if variances[param.index as usize] != ty::Variance::Invariant {
return None;
}
Some(match param.kind {
ty::GenericParamDefKind::Lifetime => {
PreciseCapturingArgKind::Lifetime(param.name)
}
ty::GenericParamDefKind::Type { .. }
| ty::GenericParamDefKind::Const { .. } => {
PreciseCapturingArgKind::Param(param.name)
}
})
}));
}
PreciseCapturingArgKind::Param(_) => PreciseCapturingArgKind::Param(arg.name()),
})))
}
_ => None,
})

Some(&*tcx.arena.alloc_slice(&captures))
} else {
None
}
})
}

fn const_param_default<'tcx>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,9 @@ fn generic_param_def_as_bound_arg<'tcx>(
/// Whether this opaque always captures lifetimes in scope.
/// Right now, this is all RPITIT and TAITs, and when the opaque
/// is coming from a span corresponding to edition 2024.
fn opaque_captures_all_in_scope_lifetimes<'tcx>(opaque: &'tcx hir::OpaqueTy<'tcx>) -> bool {
pub(super) fn opaque_captures_all_in_scope_lifetimes<'tcx>(
opaque: &'tcx hir::OpaqueTy<'tcx>,
) -> bool {
match opaque.origin {
// if the opaque has the `use<...>` syntax, the user is telling us that they only want
// to account for those lifetimes, so do not try to be clever.
Expand Down
73 changes: 53 additions & 20 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1859,17 +1859,15 @@ fn maybe_expand_private_type_alias<'tcx>(
}

pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
use rustc_hir::*;

match ty.kind {
TyKind::Never => Primitive(PrimitiveType::Never),
TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
TyKind::Ref(l, ref m) => {
hir::TyKind::Never => Primitive(PrimitiveType::Never),
hir::TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
hir::TyKind::Ref(l, ref m) => {
let lifetime = if l.is_anonymous() { None } else { Some(clean_lifetime(l, cx)) };
BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
}
TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
TyKind::Pat(inner_ty, pat) => {
hir::TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
hir::TyKind::Pat(inner_ty, pat) => {
// Local HIR pattern types should print the same way as cross-crate inlined ones,
// so lower to the canonical `rustc_middle::ty::Pattern` representation first.
let pat = match lower_ty(cx.tcx, ty).kind() {
Expand All @@ -1878,15 +1876,15 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
};
Type::Pat(Box::new(clean_ty(inner_ty, cx)), pat)
}
TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => {
hir::TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => {
let field_str = if let Some(variant) = variant {
format!("{variant}.{field}")
} else {
format!("{field}")
};
Type::FieldOf(Box::new(clean_ty(ty, cx)), field_str.into())
}
TyKind::Array(ty, const_arg) => {
hir::TyKind::Array(ty, const_arg) => {
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
// as we currently do not supply the parent generics to anonymous constants
// but do allow `ConstKind::Param`.
Expand Down Expand Up @@ -1915,12 +1913,47 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
};
Array(Box::new(clean_ty(ty, cx)), length.into())
}
TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
TyKind::OpaqueDef(ty) => {
ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
hir::TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
hir::TyKind::OpaqueDef(opaque) => {
let mut captures_explicitly = false;

let mut bounds: Vec<_> = opaque
.bounds
.iter()
.filter_map(|bound| {
if let hir::GenericBound::Use(..) = bound {
captures_explicitly = true;
}
clean_generic_bound(bound, cx)
})
.collect();

// FIXME(fmease): Doing this unconditionally is probably too expensive.
// Ideally we would only compute the effective use-bound if
// `opaque_captures_all_in_scope_lifetimes(&ty)` but that
// function is compiler-private atm (and I wish it stayed that way).
if !captures_explicitly
&& let Some(args) = cx.tcx.rendered_precise_capturing_args(opaque.def_id)
{
// FIXME(fmease): Maybe avoid dupe w/ clean_middle_opaque.
bounds.push(GenericBound::Use(
args.iter()
.map(|arg| match arg {
hir::PreciseCapturingArgKind::Lifetime(lt) => {
PreciseCapturingArg::Lifetime(Lifetime(*lt))
}
hir::PreciseCapturingArgKind::Param(param) => {
PreciseCapturingArg::Param(*param)
}
})
.collect(),
));
}

ImplTrait(bounds)
}
TyKind::Path(_) => clean_qpath(ty, cx),
TyKind::TraitObject(bounds, lifetime) => {
hir::TyKind::Path(_) => clean_qpath(ty, cx),
hir::TyKind::TraitObject(bounds, lifetime) => {
let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
let lifetime = if !lifetime.is_elided() {
Some(clean_lifetime(lifetime.pointer(), cx))
Expand All @@ -1929,15 +1962,15 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
};
DynTrait(bounds, lifetime)
}
TyKind::FnPtr(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
TyKind::UnsafeBinder(unsafe_binder_ty) => {
hir::TyKind::FnPtr(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
hir::TyKind::UnsafeBinder(unsafe_binder_ty) => {
UnsafeBinder(Box::new(clean_unsafe_binder_ty(unsafe_binder_ty, cx)))
}
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
TyKind::Infer(())
| TyKind::Err(_)
| TyKind::InferDelegation(..)
| TyKind::TraitAscription(_) => Infer,
hir::TyKind::Infer(())
| hir::TyKind::Err(_)
| hir::TyKind::InferDelegation(..)
| hir::TyKind::TraitAscription(_) => Infer,
}
}

Expand Down
Loading