Skip to content

Commit

Permalink
Auto merge of rust-lang#127658 - compiler-errors:precise-capturing-ru…
Browse files Browse the repository at this point in the history
…stdoc-cross, r=<try>

Add cross-crate precise capturing support to rustdoc

Follow-up to rust-lang#127632. Fixes rust-lang#127228.

r? `@fmease`

Tracking:
* rust-lang#123432
  • Loading branch information
bors committed Jul 12, 2024
2 parents 5d76a13 + a792b45 commit b7afd35
Show file tree
Hide file tree
Showing 17 changed files with 140 additions and 21 deletions.
7 changes: 7 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2708,6 +2708,13 @@ impl PreciseCapturingArg<'_> {
PreciseCapturingArg::Param(param) => param.hir_id,
}
}

pub fn name(self) -> Symbol {
match self {
PreciseCapturingArg::Lifetime(lt) => lt.ident.name,
PreciseCapturingArg::Param(param) => param.ident.name,
}
}
}

/// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ pub fn provide(providers: &mut Providers) {
coroutine_for_closure,
is_type_alias_impl_trait,
find_field,
rendered_precise_capturing_args,
..*providers
};
}
Expand Down Expand Up @@ -1899,3 +1900,23 @@ fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool
_ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
}
}

fn rendered_precise_capturing_args<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> Option<&'tcx [Symbol]> {
if let Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) =
tcx.opt_rpitit_info(def_id.to_def_id())
{
return tcx.rendered_precise_capturing_args(opaque_def_id);
}

tcx.hir_node_by_def_id(def_id).expect_item().expect_opaque_ty().bounds.iter().find_map(
|bound| match bound {
hir::GenericBound::Use(args, ..) => {
Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name())))
}
_ => None,
},
)
}
10 changes: 10 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<'
}
}

impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>>
ProcessQueryValue<'tcx, Option<&'tcx [T]>> for Option<DecodeIterator<'a, 'tcx, T>>
{
#[inline(always)]
fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> Option<&'tcx [T]> {
if let Some(iter) = self { Some(&*tcx.arena.alloc_from_iter(iter)) } else { None }
}
}

impl ProcessQueryValue<'_, Option<DeprecationEntry>> for Option<Deprecation> {
#[inline(always)]
fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option<DeprecationEntry> {
Expand Down Expand Up @@ -249,6 +258,7 @@ provide! { tcx, def_id, other, cdata,
.process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) }
mir_const_qualif => { table }
rendered_const => { table }
rendered_precise_capturing_args => { table }
asyncness => { table_direct }
fn_arg_names => { table }
coroutine_kind => { table_direct }
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1496,6 +1496,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.tables
.is_type_alias_impl_trait
.set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id));
self.encode_precise_capturing_args(def_id);
}
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
Expand Down Expand Up @@ -1636,12 +1637,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
<- self.tcx.assumed_wf_types_for_rpitit(def_id)
);
}
self.encode_precise_capturing_args(def_id);
}
if item.is_effects_desugaring {
self.tables.is_effects_desugaring.set(def_id.index, true);
}
}

fn encode_precise_capturing_args(&mut self, def_id: DefId) {
let Some(precise_capturing_args) = self.tcx.rendered_precise_capturing_args(def_id) else {
return;
};

record_array!(self.tables.rendered_precise_capturing_args[def_id] <- precise_capturing_args);
}

fn encode_mir(&mut self) {
if self.is_proc_macro {
return;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ define_tables! {
coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>,
mir_const_qualif: Table<DefIndex, LazyValue<mir::ConstQualifs>>,
rendered_const: Table<DefIndex, LazyValue<String>>,
rendered_precise_capturing_args: Table<DefIndex, LazyArray<Symbol>>,
asyncness: Table<DefIndex, ty::Asyncness>,
fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
coroutine_kind: Table<DefIndex, hir::CoroutineKind>,
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1261,13 +1261,20 @@ rustc_queries! {
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}

/// Gets the rendered value of the specified constant or associated constant.
/// Used by rustdoc.
query rendered_const(def_id: DefId) -> &'tcx String {
arena_cache
desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
/// Gets the rendered precise capturing args for an opaque for use in rustdoc.
query rendered_precise_capturing_args(def_id: DefId) -> Option<&'tcx [Symbol]> {
desc { |tcx| "computing precise capturing args for `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}

query impl_parent(def_id: DefId) -> Option<DefId> {
desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
Expand Down
2 changes: 2 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ ignore = [
"/tests/rustdoc-ui/", # Some have syntax errors, some are whitespace-sensitive.
"/tests/ui/", # Some have syntax errors, some are whitespace-sensitive.
"/tests/ui-fulldeps/", # Some are whitespace-sensitive (e.g. `// ~ERROR` comments).
# #[cfg(bootstrap)] so that t-release sees this when they search for it
"/tests/rustdoc-json/impl-trait-precise-capturing.rs",

# Do not format submodules.
# FIXME: sync submodule list with tidy/bootstrap/etc
Expand Down
39 changes: 20 additions & 19 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,9 @@ fn clean_generic_bound<'tcx>(

GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
}
// FIXME(precise_capturing): Implement rustdoc support
hir::GenericBound::Use(..) => return None,
hir::GenericBound::Use(args, ..) => {
GenericBound::Use(args.iter().map(|arg| arg.name()).collect())
}
})
}

Expand Down Expand Up @@ -460,13 +461,7 @@ fn clean_projection<'tcx>(
def_id: Option<DefId>,
) -> Type {
if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) {
let bounds = cx
.tcx
.explicit_item_bounds(ty.skip_binder().def_id)
.iter_instantiated_copied(cx.tcx, ty.skip_binder().args)
.map(|(pred, _)| pred)
.collect::<Vec<_>>();
return clean_middle_opaque_bounds(cx, bounds);
return clean_middle_opaque_bounds(cx, ty.skip_binder().def_id, ty.skip_binder().args);
}

let trait_ = clean_trait_ref_with_constraints(
Expand Down Expand Up @@ -2242,13 +2237,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
*cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the bounds associated with the def_id.
let bounds = cx
.tcx
.explicit_item_bounds(def_id)
.iter_instantiated_copied(cx.tcx, args)
.map(|(bound, _)| bound)
.collect::<Vec<_>>();
let ty = clean_middle_opaque_bounds(cx, bounds);
let ty = clean_middle_opaque_bounds(cx, def_id, args);
if let Some(count) = cx.current_type_aliases.get_mut(&def_id) {
*count -= 1;
if *count == 0 {
Expand All @@ -2271,12 +2260,20 @@ pub(crate) fn clean_middle_ty<'tcx>(

fn clean_middle_opaque_bounds<'tcx>(
cx: &mut DocContext<'tcx>,
bounds: Vec<ty::Clause<'tcx>>,
impl_trait_def_id: DefId,
args: ty::GenericArgsRef<'tcx>,
) -> Type {
let mut has_sized = false;

let bounds: Vec<_> = cx
.tcx
.explicit_item_bounds(impl_trait_def_id)
.iter_instantiated_copied(cx.tcx, args)
.collect();

let mut bounds = bounds
.iter()
.filter_map(|bound| {
.filter_map(|(bound, _)| {
let bound_predicate = bound.kind();
let trait_ref = match bound_predicate.skip_binder() {
ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
Expand All @@ -2295,7 +2292,7 @@ fn clean_middle_opaque_bounds<'tcx>(

let bindings: ThinVec<_> = bounds
.iter()
.filter_map(|bound| {
.filter_map(|(bound, _)| {
if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() {
if proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() {
Some(AssocItemConstraint {
Expand Down Expand Up @@ -2335,6 +2332,10 @@ fn clean_middle_opaque_bounds<'tcx>(
bounds.insert(0, GenericBound::sized(cx));
}

if let Some(args) = cx.tcx.rendered_precise_capturing_args(impl_trait_def_id) {
bounds.push(GenericBound::Use(args.to_vec()));
}

ImplTrait(bounds)
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub(crate) fn merge_bounds(
!bounds.iter_mut().any(|b| {
let trait_ref = match *b {
clean::GenericBound::TraitBound(ref mut tr, _) => tr,
clean::GenericBound::Outlives(..) => return false,
clean::GenericBound::Outlives(..) | clean::GenericBound::Use(_) => return false,
};
// If this QPath's trait `trait_did` is the same as, or a supertrait
// of, the bound's trait `did` then we can keep going, otherwise
Expand Down
2 changes: 2 additions & 0 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,8 @@ impl Eq for Attributes {}
pub(crate) enum GenericBound {
TraitBound(PolyTrait, hir::TraitBoundModifier),
Outlives(Lifetime),
/// `use<'a, T>` precise-capturing bound syntax
Use(Vec<Symbol>),
}

impl GenericBound {
Expand Down
14 changes: 14 additions & 0 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,20 @@ impl clean::GenericBound {
})?;
ty.print(cx).fmt(f)
}
clean::GenericBound::Use(args) => {
if f.alternate() {
f.write_str("use<")?;
} else {
f.write_str("use&lt;")?;
}
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
arg.fmt(f)?;
}
if f.alternate() { f.write_str(">") } else { f.write_str("&gt;") }
}
})
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ impl FromWithTcx<clean::GenericBound> for GenericBound {
}
}
Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)),
Use(args) => GenericBound::Use(args.into_iter().map(|arg| arg.to_string()).collect()),
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/rustdoc-json-types/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use std::path::PathBuf;

/// rustdoc format-version.
pub const FORMAT_VERSION: u32 = 31;
pub const FORMAT_VERSION: u32 = 32;

/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow
Expand Down Expand Up @@ -538,6 +538,8 @@ pub enum GenericBound {
modifier: TraitBoundModifier,
},
Outlives(String),
/// `use<'a, T>` precise-capturing bound syntax
Use(Vec<String>),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
Expand Down
1 change: 1 addition & 0 deletions src/tools/jsondoclint/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ impl<'a> Validator<'a> {
generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
}
GenericBound::Outlives(_) => {}
GenericBound::Use(_) => {}
}
}

Expand Down
6 changes: 6 additions & 0 deletions tests/rustdoc-json/impl-trait-precise-capturing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![feature(precise_capturing)]

// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\"
// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\"
// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\"
pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}
7 changes: 7 additions & 0 deletions tests/rustdoc/auxiliary/precise-capturing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#![feature(precise_capturing)]

pub fn cross_crate_empty() -> impl Sized + use<> {}

pub fn cross_crate_missing() -> impl Sized {}

pub fn cross_crate_args<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}
27 changes: 27 additions & 0 deletions tests/rustdoc/impl-trait-precise-capturing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//@ aux-build:precise-capturing.rs

#![crate_name = "foo"]
#![feature(precise_capturing)]

extern crate precise_capturing;

//@ has foo/fn.two.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'b, 'a>"
pub fn two<'a, 'b, 'c>() -> impl Sized + use<'b, 'a /* no 'c */> {}

//@ has foo/fn.params.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'a, T, N>"
pub fn params<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}

//@ has foo/fn.none.html '//section[@id="main-content"]//pre' "-> impl Sized + use<>"
pub fn none() -> impl Sized + use<> {}

//@ has foo/fn.first.html '//section[@id="main-content"]//pre' "-> impl use<> + Sized"
pub fn first() -> impl use<> + Sized {}

//@ has foo/fn.cross_crate_empty.html '//section[@id="main-content"]//pre' "-> impl Sized + use<>"
pub use precise_capturing::cross_crate_empty;

//@ has foo/fn.cross_crate_missing.html '//section[@id="main-content"]//pre' "-> impl Sized"
pub use precise_capturing::cross_crate_missing;

//@ has foo/fn.cross_crate_args.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'a, T, N>"
pub use precise_capturing::cross_crate_args;

0 comments on commit b7afd35

Please sign in to comment.