Rollup merge of #137956 - compiler-errors:rtn-rustdoc, r=fmease
Add RTN support to rustdoc This adds support to rustdoc and rustdoc-json for rendering `(..)` RTN (return type notation) style generics. --- Cleaning `rustc_middle::ty::Ty` is not correct still, though, and ends up rendering a function like: ```rust pub fn foreign<T: Foreign<bar(..): Send>>() where <T as Foreign>::bar(..): 'static, T::bar(..): Sync, ``` Into this: ```rust pub fn foreign<T>() where T: Foreign, impl Future<Output = ()>: Send + 'static + Sync, ``` This is because `clean_middle_ty` doesn't actually have sufficient context about whether the RPITIT is in its "defining scope" or not, so we don't know if the type was originally written like `-> impl Trait` or with RTN like `T::method(..)`. Partially addresses #123996 (i.e., HIR side, not middle::ty one)
This commit is contained in:
commit
8882dac342
10 changed files with 98 additions and 32 deletions
|
@ -252,7 +252,9 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||||
// def-ID that will be used to determine the traits/predicates in
|
// def-ID that will be used to determine the traits/predicates in
|
||||||
// scope. This is derived from the enclosing item-like thing.
|
// scope. This is derived from the enclosing item-like thing.
|
||||||
let env_def_id = tcx.hir_get_parent_item(hir_ty.hir_id);
|
let env_def_id = tcx.hir_get_parent_item(hir_ty.hir_id);
|
||||||
collect::ItemCtxt::new(tcx, env_def_id.def_id).lower_ty(hir_ty)
|
collect::ItemCtxt::new(tcx, env_def_id.def_id)
|
||||||
|
.lowerer()
|
||||||
|
.lower_ty_maybe_return_type_notation(hir_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is for rustdoc.
|
/// This is for rustdoc.
|
||||||
|
|
|
@ -1488,6 +1488,9 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
|
||||||
// The only time this happens is if we're inside the rustdoc for Fn(),
|
// The only time this happens is if we're inside the rustdoc for Fn(),
|
||||||
// which only has one associated type, which is not a GAT, so whatever.
|
// which only has one associated type, which is not a GAT, so whatever.
|
||||||
}
|
}
|
||||||
|
GenericArgs::ReturnTypeNotation => {
|
||||||
|
// Never move these.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bounds.extend(mem::take(pred_bounds));
|
bounds.extend(mem::take(pred_bounds));
|
||||||
false
|
false
|
||||||
|
@ -2553,15 +2556,8 @@ fn clean_generic_args<'tcx>(
|
||||||
generic_args: &hir::GenericArgs<'tcx>,
|
generic_args: &hir::GenericArgs<'tcx>,
|
||||||
cx: &mut DocContext<'tcx>,
|
cx: &mut DocContext<'tcx>,
|
||||||
) -> GenericArgs {
|
) -> GenericArgs {
|
||||||
// FIXME(return_type_notation): Fix RTN parens rendering
|
match generic_args.parenthesized {
|
||||||
if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() {
|
hir::GenericArgsParentheses::No => {
|
||||||
let inputs = inputs.iter().map(|x| clean_ty(x, cx)).collect();
|
|
||||||
let output = match output.kind {
|
|
||||||
hir::TyKind::Tup(&[]) => None,
|
|
||||||
_ => Some(Box::new(clean_ty(output, cx))),
|
|
||||||
};
|
|
||||||
GenericArgs::Parenthesized { inputs, output }
|
|
||||||
} else {
|
|
||||||
let args = generic_args
|
let args = generic_args
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -2584,6 +2580,19 @@ fn clean_generic_args<'tcx>(
|
||||||
.collect::<ThinVec<_>>();
|
.collect::<ThinVec<_>>();
|
||||||
GenericArgs::AngleBracketed { args, constraints }
|
GenericArgs::AngleBracketed { args, constraints }
|
||||||
}
|
}
|
||||||
|
hir::GenericArgsParentheses::ParenSugar => {
|
||||||
|
let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() else {
|
||||||
|
bug!();
|
||||||
|
};
|
||||||
|
let inputs = inputs.iter().map(|x| clean_ty(x, cx)).collect();
|
||||||
|
let output = match output.kind {
|
||||||
|
hir::TyKind::Tup(&[]) => None,
|
||||||
|
_ => Some(Box::new(clean_ty(output, cx))),
|
||||||
|
};
|
||||||
|
GenericArgs::Parenthesized { inputs, output }
|
||||||
|
}
|
||||||
|
hir::GenericArgsParentheses::ReturnTypeNotation => GenericArgs::ReturnTypeNotation,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_path_segment<'tcx>(
|
fn clean_path_segment<'tcx>(
|
||||||
|
|
|
@ -102,6 +102,10 @@ pub(crate) fn merge_bounds(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
PP::ReturnTypeNotation => {
|
||||||
|
// Cannot merge bounds with RTN.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
|
|
|
@ -2259,8 +2259,12 @@ impl GenericArg {
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub(crate) enum GenericArgs {
|
pub(crate) enum GenericArgs {
|
||||||
|
/// `<args, constraints = ..>`
|
||||||
AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
|
AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
|
||||||
|
/// `(inputs) -> output`
|
||||||
Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
|
Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
|
||||||
|
/// `(..)`
|
||||||
|
ReturnTypeNotation,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenericArgs {
|
impl GenericArgs {
|
||||||
|
@ -2270,6 +2274,7 @@ impl GenericArgs {
|
||||||
args.is_empty() && constraints.is_empty()
|
args.is_empty() && constraints.is_empty()
|
||||||
}
|
}
|
||||||
GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
|
GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
|
||||||
|
GenericArgs::ReturnTypeNotation => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
|
pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
|
||||||
|
@ -2294,6 +2299,7 @@ impl GenericArgs {
|
||||||
})
|
})
|
||||||
.into_iter(),
|
.into_iter(),
|
||||||
),
|
),
|
||||||
|
GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2305,8 +2311,10 @@ impl<'a> IntoIterator for &'a GenericArgs {
|
||||||
match self {
|
match self {
|
||||||
GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
|
GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
|
||||||
GenericArgs::Parenthesized { inputs, .. } => {
|
GenericArgs::Parenthesized { inputs, .. } => {
|
||||||
|
// FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>`
|
||||||
Box::new(inputs.iter().cloned().map(GenericArg::Type))
|
Box::new(inputs.iter().cloned().map(GenericArg::Type))
|
||||||
}
|
}
|
||||||
|
GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -332,6 +332,9 @@ impl clean::GenericArgs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clean::GenericArgs::ReturnTypeNotation => {
|
||||||
|
f.write_str("(..)")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
|
|
@ -176,6 +176,7 @@ impl FromClean<clean::GenericArgs> for GenericArgs {
|
||||||
inputs: inputs.into_json(renderer),
|
inputs: inputs.into_json(renderer),
|
||||||
output: output.map(|a| (*a).into_json(renderer)),
|
output: output.map(|a| (*a).into_json(renderer)),
|
||||||
},
|
},
|
||||||
|
ReturnTypeNotation => GenericArgs::ReturnTypeNotation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
|
||||||
/// This integer is incremented with every breaking change to the API,
|
/// This integer is incremented with every breaking change to the API,
|
||||||
/// and is returned along with the JSON blob as [`Crate::format_version`].
|
/// and is returned along with the JSON blob as [`Crate::format_version`].
|
||||||
/// Consuming code should assert that this value matches the format version(s) that it supports.
|
/// Consuming code should assert that this value matches the format version(s) that it supports.
|
||||||
pub const FORMAT_VERSION: u32 = 41;
|
pub const FORMAT_VERSION: u32 = 42;
|
||||||
|
|
||||||
/// The root of the emitted JSON blob.
|
/// The root of the emitted JSON blob.
|
||||||
///
|
///
|
||||||
|
@ -229,6 +229,8 @@ pub enum GenericArgs {
|
||||||
/// The output type provided after the `->`, if present.
|
/// The output type provided after the `->`, if present.
|
||||||
output: Option<Type>,
|
output: Option<Type>,
|
||||||
},
|
},
|
||||||
|
/// `T::method(..)`
|
||||||
|
ReturnTypeNotation,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One argument in a list of generic arguments to a path segment.
|
/// One argument in a list of generic arguments to a path segment.
|
||||||
|
|
|
@ -326,6 +326,7 @@ impl<'a> Validator<'a> {
|
||||||
self.check_type(o);
|
self.check_type(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GenericArgs::ReturnTypeNotation => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
tests/rustdoc-json/return-type-notation.rs
Normal file
18
tests/rustdoc-json/return-type-notation.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(return_type_notation)]
|
||||||
|
|
||||||
|
pub trait Foo {
|
||||||
|
async fn bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.args.angle_bracketed.constraints[0].args" '"return_type_notation"'
|
||||||
|
//@ ismany "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[*].bound_predicate.type.qualified_path.args" '"return_type_notation"' '"return_type_notation"'
|
||||||
|
pub fn foo<T: Foo<bar(..): Send>>()
|
||||||
|
where
|
||||||
|
<T as Foo>::bar(..): 'static,
|
||||||
|
T::bar(..): Sync,
|
||||||
|
{
|
||||||
|
}
|
18
tests/rustdoc/return-type-notation.rs
Normal file
18
tests/rustdoc/return-type-notation.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(return_type_notation)]
|
||||||
|
|
||||||
|
pub trait Foo {
|
||||||
|
async fn bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@ has "return_type_notation/fn.foo.html"
|
||||||
|
//@ has - '//pre[@class="rust item-decl"]' "pub fn foo<T: Foo<bar(..): Send>>()"
|
||||||
|
//@ has - '//pre[@class="rust item-decl"]' "where <T as Foo>::bar(..): 'static, T::bar(..): Sync"
|
||||||
|
pub fn foo<T: Foo<bar(..): Send>>()
|
||||||
|
where
|
||||||
|
<T as Foo>::bar(..): 'static,
|
||||||
|
T::bar(..): Sync,
|
||||||
|
{
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue