Skip to content

Commit 34769e6

Browse files
committed
Auto merge of #127658 - compiler-errors:precise-capturing-rustdoc-cross, r=<try>
Add cross-crate precise capturing support to rustdoc Follow-up to #127632. Fixes #127228. r? `@fmease` Tracking: * #123432
2 parents 5d76a13 + f29c637 commit 34769e6

File tree

17 files changed

+140
-21
lines changed

17 files changed

+140
-21
lines changed

Diff for: compiler/rustc_hir/src/hir.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2708,6 +2708,13 @@ impl PreciseCapturingArg<'_> {
27082708
PreciseCapturingArg::Param(param) => param.hir_id,
27092709
}
27102710
}
2711+
2712+
pub fn name(self) -> Symbol {
2713+
match self {
2714+
PreciseCapturingArg::Lifetime(lt) => lt.ident.name,
2715+
PreciseCapturingArg::Param(param) => param.ident.name,
2716+
}
2717+
}
27112718
}
27122719

27132720
/// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param

Diff for: compiler/rustc_hir_analysis/src/collect.rs

+21
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub fn provide(providers: &mut Providers) {
8686
coroutine_for_closure,
8787
is_type_alias_impl_trait,
8888
find_field,
89+
rendered_precise_capturing_args,
8990
..*providers
9091
};
9192
}
@@ -1899,3 +1900,23 @@ fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool
18991900
_ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
19001901
}
19011902
}
1903+
1904+
fn rendered_precise_capturing_args<'tcx>(
1905+
tcx: TyCtxt<'tcx>,
1906+
def_id: LocalDefId,
1907+
) -> Option<&'tcx [Symbol]> {
1908+
if let Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) =
1909+
tcx.opt_rpitit_info(def_id.to_def_id())
1910+
{
1911+
return tcx.rendered_precise_capturing_args(opaque_def_id);
1912+
}
1913+
1914+
tcx.hir_node_by_def_id(def_id).expect_item().expect_opaque_ty().bounds.iter().find_map(
1915+
|bound| match bound {
1916+
hir::GenericBound::Use(args, ..) => {
1917+
Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name())))
1918+
}
1919+
_ => None,
1920+
},
1921+
)
1922+
}

Diff for: compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+10
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<'
7272
}
7373
}
7474

75+
impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>>
76+
ProcessQueryValue<'tcx, Option<&'tcx [T]>> for Option<DecodeIterator<'a, 'tcx, T>>
77+
{
78+
#[inline(always)]
79+
fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> Option<&'tcx [T]> {
80+
if let Some(iter) = self { Some(&*tcx.arena.alloc_from_iter(iter)) } else { None }
81+
}
82+
}
83+
7584
impl ProcessQueryValue<'_, Option<DeprecationEntry>> for Option<Deprecation> {
7685
#[inline(always)]
7786
fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option<DeprecationEntry> {
@@ -249,6 +258,7 @@ provide! { tcx, def_id, other, cdata,
249258
.process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) }
250259
mir_const_qualif => { table }
251260
rendered_const => { table }
261+
rendered_precise_capturing_args => { table }
252262
asyncness => { table_direct }
253263
fn_arg_names => { table }
254264
coroutine_kind => { table_direct }

Diff for: compiler/rustc_metadata/src/rmeta/encoder.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14961496
self.tables
14971497
.is_type_alias_impl_trait
14981498
.set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id));
1499+
self.encode_precise_capturing_args(def_id);
14991500
}
15001501
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
15011502
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
@@ -1635,13 +1636,22 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
16351636
self.tables.assumed_wf_types_for_rpitit[def_id]
16361637
<- self.tcx.assumed_wf_types_for_rpitit(def_id)
16371638
);
1639+
self.encode_precise_capturing_args(def_id);
16381640
}
16391641
}
16401642
if item.is_effects_desugaring {
16411643
self.tables.is_effects_desugaring.set(def_id.index, true);
16421644
}
16431645
}
16441646

1647+
fn encode_precise_capturing_args(&mut self, def_id: DefId) {
1648+
let Some(precise_capturing_args) = self.tcx.rendered_precise_capturing_args(def_id) else {
1649+
return;
1650+
};
1651+
1652+
record_array!(self.tables.rendered_precise_capturing_args[def_id] <- precise_capturing_args);
1653+
}
1654+
16451655
fn encode_mir(&mut self) {
16461656
if self.is_proc_macro {
16471657
return;

Diff for: compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ define_tables! {
442442
coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>,
443443
mir_const_qualif: Table<DefIndex, LazyValue<mir::ConstQualifs>>,
444444
rendered_const: Table<DefIndex, LazyValue<String>>,
445+
rendered_precise_capturing_args: Table<DefIndex, LazyArray<Symbol>>,
445446
asyncness: Table<DefIndex, ty::Asyncness>,
446447
fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
447448
coroutine_kind: Table<DefIndex, hir::CoroutineKind>,

Diff for: compiler/rustc_middle/src/query/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1261,13 +1261,20 @@ rustc_queries! {
12611261
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
12621262
separate_provide_extern
12631263
}
1264+
12641265
/// Gets the rendered value of the specified constant or associated constant.
12651266
/// Used by rustdoc.
12661267
query rendered_const(def_id: DefId) -> &'tcx String {
12671268
arena_cache
12681269
desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) }
12691270
separate_provide_extern
12701271
}
1272+
/// Gets the rendered precise capturing args for an opaque for use in rustdoc.
1273+
query rendered_precise_capturing_args(def_id: DefId) -> Option<&'tcx [Symbol]> {
1274+
desc { |tcx| "computing precise capturing args for `{}`", tcx.def_path_str(def_id) }
1275+
separate_provide_extern
1276+
}
1277+
12711278
query impl_parent(def_id: DefId) -> Option<DefId> {
12721279
desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
12731280
separate_provide_extern

Diff for: rustfmt.toml

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ ignore = [
2222
"/tests/rustdoc-ui/", # Some have syntax errors, some are whitespace-sensitive.
2323
"/tests/ui/", # Some have syntax errors, some are whitespace-sensitive.
2424
"/tests/ui-fulldeps/", # Some are whitespace-sensitive (e.g. `// ~ERROR` comments).
25+
# #[cfg(bootstrap)] so that t-release sees this when they search for it
26+
"/tests/rustdoc-json/impl-trait-precise-capturing.rs",
2527

2628
# Do not format submodules.
2729
# FIXME: sync submodule list with tidy/bootstrap/etc

Diff for: src/librustdoc/clean/mod.rs

+20-19
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,9 @@ fn clean_generic_bound<'tcx>(
228228

229229
GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
230230
}
231-
// FIXME(precise_capturing): Implement rustdoc support
232-
hir::GenericBound::Use(..) => return None,
231+
hir::GenericBound::Use(args, ..) => {
232+
GenericBound::Use(args.iter().map(|arg| arg.name()).collect())
233+
}
233234
})
234235
}
235236

@@ -460,13 +461,7 @@ fn clean_projection<'tcx>(
460461
def_id: Option<DefId>,
461462
) -> Type {
462463
if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) {
463-
let bounds = cx
464-
.tcx
465-
.explicit_item_bounds(ty.skip_binder().def_id)
466-
.iter_instantiated_copied(cx.tcx, ty.skip_binder().args)
467-
.map(|(pred, _)| pred)
468-
.collect::<Vec<_>>();
469-
return clean_middle_opaque_bounds(cx, bounds);
464+
return clean_middle_opaque_bounds(cx, ty.skip_binder().def_id, ty.skip_binder().args);
470465
}
471466

472467
let trait_ = clean_trait_ref_with_constraints(
@@ -2242,13 +2237,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
22422237
*cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
22432238
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
22442239
// by looking up the bounds associated with the def_id.
2245-
let bounds = cx
2246-
.tcx
2247-
.explicit_item_bounds(def_id)
2248-
.iter_instantiated_copied(cx.tcx, args)
2249-
.map(|(bound, _)| bound)
2250-
.collect::<Vec<_>>();
2251-
let ty = clean_middle_opaque_bounds(cx, bounds);
2240+
let ty = clean_middle_opaque_bounds(cx, def_id, args);
22522241
if let Some(count) = cx.current_type_aliases.get_mut(&def_id) {
22532242
*count -= 1;
22542243
if *count == 0 {
@@ -2271,12 +2260,20 @@ pub(crate) fn clean_middle_ty<'tcx>(
22712260

22722261
fn clean_middle_opaque_bounds<'tcx>(
22732262
cx: &mut DocContext<'tcx>,
2274-
bounds: Vec<ty::Clause<'tcx>>,
2263+
impl_trait_def_id: DefId,
2264+
args: ty::GenericArgsRef<'tcx>,
22752265
) -> Type {
22762266
let mut has_sized = false;
2267+
2268+
let bounds: Vec<_> = cx
2269+
.tcx
2270+
.explicit_item_bounds(impl_trait_def_id)
2271+
.iter_instantiated_copied(cx.tcx, args)
2272+
.collect();
2273+
22772274
let mut bounds = bounds
22782275
.iter()
2279-
.filter_map(|bound| {
2276+
.filter_map(|(bound, _)| {
22802277
let bound_predicate = bound.kind();
22812278
let trait_ref = match bound_predicate.skip_binder() {
22822279
ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
@@ -2295,7 +2292,7 @@ fn clean_middle_opaque_bounds<'tcx>(
22952292

22962293
let bindings: ThinVec<_> = bounds
22972294
.iter()
2298-
.filter_map(|bound| {
2295+
.filter_map(|(bound, _)| {
22992296
if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() {
23002297
if proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() {
23012298
Some(AssocItemConstraint {
@@ -2335,6 +2332,10 @@ fn clean_middle_opaque_bounds<'tcx>(
23352332
bounds.insert(0, GenericBound::sized(cx));
23362333
}
23372334

2335+
if let Some(args) = cx.tcx.rendered_precise_capturing_args(impl_trait_def_id) {
2336+
bounds.push(GenericBound::Use(args.to_vec()));
2337+
}
2338+
23382339
ImplTrait(bounds)
23392340
}
23402341

Diff for: src/librustdoc/clean/simplify.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub(crate) fn merge_bounds(
7979
!bounds.iter_mut().any(|b| {
8080
let trait_ref = match *b {
8181
clean::GenericBound::TraitBound(ref mut tr, _) => tr,
82-
clean::GenericBound::Outlives(..) => return false,
82+
clean::GenericBound::Outlives(..) | clean::GenericBound::Use(_) => return false,
8383
};
8484
// If this QPath's trait `trait_did` is the same as, or a supertrait
8585
// of, the bound's trait `did` then we can keep going, otherwise

Diff for: src/librustdoc/clean/types.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,8 @@ impl Eq for Attributes {}
12441244
pub(crate) enum GenericBound {
12451245
TraitBound(PolyTrait, hir::TraitBoundModifier),
12461246
Outlives(Lifetime),
1247+
/// `use<'a, T>` precise-capturing bound syntax
1248+
Use(Vec<Symbol>),
12471249
}
12481250

12491251
impl GenericBound {

Diff for: src/librustdoc/html/format.rs

+14
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,20 @@ impl clean::GenericBound {
412412
})?;
413413
ty.print(cx).fmt(f)
414414
}
415+
clean::GenericBound::Use(args) => {
416+
if f.alternate() {
417+
f.write_str("use<")?;
418+
} else {
419+
f.write_str("use&lt;")?;
420+
}
421+
for (i, arg) in args.iter().enumerate() {
422+
if i > 0 {
423+
write!(f, ", ")?;
424+
}
425+
arg.fmt(f)?;
426+
}
427+
if f.alternate() { f.write_str(">") } else { f.write_str("&gt;") }
428+
}
415429
})
416430
}
417431
}

Diff for: src/librustdoc/json/conversions.rs

+1
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ impl FromWithTcx<clean::GenericBound> for GenericBound {
542542
}
543543
}
544544
Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)),
545+
Use(args) => GenericBound::Use(args.into_iter().map(|arg| arg.to_string()).collect()),
545546
}
546547
}
547548
}

Diff for: src/rustdoc-json-types/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
88
use std::path::PathBuf;
99

1010
/// rustdoc format-version.
11-
pub const FORMAT_VERSION: u32 = 31;
11+
pub const FORMAT_VERSION: u32 = 32;
1212

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

543545
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]

Diff for: src/tools/jsondoclint/src/validator.rs

+1
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ impl<'a> Validator<'a> {
298298
generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
299299
}
300300
GenericBound::Outlives(_) => {}
301+
GenericBound::Use(_) => {}
301302
}
302303
}
303304

Diff for: tests/rustdoc-json/impl-trait-precise-capturing.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![feature(precise_capturing)]
2+
3+
// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\"
4+
// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\"
5+
// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\"
6+
pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}

Diff for: tests/rustdoc/auxiliary/precise-capturing.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(precise_capturing)]
2+
3+
pub fn cross_crate_empty() -> impl Sized + use<> {}
4+
5+
pub fn cross_crate_missing() -> impl Sized {}
6+
7+
pub fn cross_crate_args<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}

Diff for: tests/rustdoc/impl-trait-precise-capturing.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//@ aux-build:precise-capturing.rs
2+
3+
#![crate_name = "foo"]
4+
#![feature(precise_capturing)]
5+
6+
extern crate precise_capturing;
7+
8+
//@ has foo/fn.two.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'b, 'a>"
9+
pub fn two<'a, 'b, 'c>() -> impl Sized + use<'b, 'a /* no 'c */> {}
10+
11+
//@ has foo/fn.params.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'a, T, N>"
12+
pub fn params<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}
13+
14+
//@ has foo/fn.none.html '//section[@id="main-content"]//pre' "-> impl Sized + use<>"
15+
pub fn none() -> impl Sized + use<> {}
16+
17+
//@ has foo/fn.first.html '//section[@id="main-content"]//pre' "-> impl use<> + Sized"
18+
pub fn first() -> impl use<> + Sized {}
19+
20+
//@ has foo/fn.cross_crate_empty.html '//section[@id="main-content"]//pre' "-> impl Sized + use<>"
21+
pub use precise_capturing::cross_crate_empty;
22+
23+
//@ has foo/fn.cross_crate_missing.html '//section[@id="main-content"]//pre' "-> impl Sized"
24+
pub use precise_capturing::cross_crate_missing;
25+
26+
//@ has foo/fn.cross_crate_args.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'a, T, N>"
27+
pub use precise_capturing::cross_crate_args;

0 commit comments

Comments
 (0)