diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d57fad6ba4c2d..4561f9d9b49df 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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 diff --git a/rustfmt.toml b/rustfmt.toml index b15ffdca38a06..e060fd8fe8bfa 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -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 diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index aa596897fc42f..98ce268a77466 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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()) + } }) } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 58eef36677b23..1b7d84add1f85 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -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 diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index fe01d17b08a8c..a31adc9949a3f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -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), } impl GenericBound { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 4268fadd6c59c..e811e0bf537ad 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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<")?; + } + 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(">") } + } }) } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 5111e363c522e..4ab0df3670859 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -542,6 +542,7 @@ impl FromWithTcx for GenericBound { } } Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)), + Use(args) => GenericBound::Use(args.into_iter().map(|arg| arg.to_string()).collect()), } } } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 89115d4d7d667..6fd23b60c8ad6 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -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 @@ -538,6 +538,8 @@ pub enum GenericBound { modifier: TraitBoundModifier, }, Outlives(String), + /// `use<'a, T>` precise-capturing bound syntax + Use(Vec), } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index cd011dce7844e..ea1e573384b82 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -298,6 +298,7 @@ impl<'a> Validator<'a> { generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } GenericBound::Outlives(_) => {} + GenericBound::Use(_) => {} } } diff --git a/tests/rustdoc-json/impl-trait-precise-capturing.rs b/tests/rustdoc-json/impl-trait-precise-capturing.rs new file mode 100644 index 0000000000000..bf98868d1453d --- /dev/null +++ b/tests/rustdoc-json/impl-trait-precise-capturing.rs @@ -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> {} diff --git a/tests/rustdoc/impl-trait-precise-capturing.rs b/tests/rustdoc/impl-trait-precise-capturing.rs new file mode 100644 index 0000000000000..d1987a555c151 --- /dev/null +++ b/tests/rustdoc/impl-trait-precise-capturing.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] +#![feature(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 {}