about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-03-03 18:44:02 +0000
committerMichael Goulet <michael@errs.io>2025-03-15 18:13:27 +0000
commite3ac1fa81abd321abe193f491ed06c7d388f68fe (patch)
treef3c465579965ba4d01cef6aa639e8844e1a265a2
parent4d30011f6c616be074ba655a75e5d55441232bbb (diff)
downloadrust-e3ac1fa81abd321abe193f491ed06c7d388f68fe.tar.gz
rust-e3ac1fa81abd321abe193f491ed06c7d388f68fe.zip
Add RTN support to rustdoc
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs4
-rw-r--r--src/librustdoc/clean/mod.rs69
-rw-r--r--src/librustdoc/clean/simplify.rs4
-rw-r--r--src/librustdoc/clean/types.rs8
-rw-r--r--src/librustdoc/html/format.rs3
-rw-r--r--src/librustdoc/json/conversions.rs1
-rw-r--r--src/rustdoc-json-types/lib.rs4
-rw-r--r--src/tools/jsondoclint/src/validator.rs1
-rw-r--r--tests/rustdoc-json/return-type-notation.rs18
-rw-r--r--tests/rustdoc/return-type-notation.rs18
10 files changed, 98 insertions, 32 deletions
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index cb3cdc5e8d3..e7ecd727a85 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -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
     // scope. This is derived from the enclosing item-like thing.
     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.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0f476c8c9ff..929402d4170 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -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(),
                                 // which only has one associated type, which is not a GAT, so whatever.
                             }
+                            GenericArgs::ReturnTypeNotation => {
+                                // Never move these.
+                            }
                         }
                         bounds.extend(mem::take(pred_bounds));
                         false
@@ -2553,36 +2556,42 @@ fn clean_generic_args<'tcx>(
     generic_args: &hir::GenericArgs<'tcx>,
     cx: &mut DocContext<'tcx>,
 ) -> GenericArgs {
-    // FIXME(return_type_notation): Fix RTN parens rendering
-    if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() {
-        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
-            .args
-            .iter()
-            .map(|arg| match arg {
-                hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
-                    GenericArg::Lifetime(clean_lifetime(lt, cx))
-                }
-                hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
-                hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)),
-                hir::GenericArg::Const(ct) => {
-                    GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), cx)))
-                }
-                hir::GenericArg::Infer(_inf) => GenericArg::Infer,
-            })
-            .collect();
-        let constraints = generic_args
-            .constraints
-            .iter()
-            .map(|c| clean_assoc_item_constraint(c, cx))
-            .collect::<ThinVec<_>>();
-        GenericArgs::AngleBracketed { args, constraints }
+    match generic_args.parenthesized {
+        hir::GenericArgsParentheses::No => {
+            let args = generic_args
+                .args
+                .iter()
+                .map(|arg| match arg {
+                    hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
+                        GenericArg::Lifetime(clean_lifetime(lt, cx))
+                    }
+                    hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+                    hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)),
+                    hir::GenericArg::Const(ct) => {
+                        GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), cx)))
+                    }
+                    hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+                })
+                .collect();
+            let constraints = generic_args
+                .constraints
+                .iter()
+                .map(|c| clean_assoc_item_constraint(c, cx))
+                .collect::<ThinVec<_>>();
+            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,
     }
 }
 
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index b8db82e540c..41943b94d1e 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -102,6 +102,10 @@ pub(crate) fn merge_bounds(
                     }
                 }
             },
+            PP::ReturnTypeNotation => {
+                // Cannot merge bounds with RTN.
+                return false;
+            }
         };
         true
     })
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 228d9108e4e..3f9023659db 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2259,8 +2259,12 @@ impl GenericArg {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) enum GenericArgs {
+    /// `<args, constraints = ..>`
     AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
+    /// `(inputs) -> output`
     Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
+    /// `(..)`
+    ReturnTypeNotation,
 }
 
 impl GenericArgs {
@@ -2270,6 +2274,7 @@ impl GenericArgs {
                 args.is_empty() && constraints.is_empty()
             }
             GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
+            GenericArgs::ReturnTypeNotation => false,
         }
     }
     pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
@@ -2294,6 +2299,7 @@ impl GenericArgs {
                     })
                     .into_iter(),
             ),
+            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
         }
     }
 }
@@ -2305,8 +2311,10 @@ impl<'a> IntoIterator for &'a GenericArgs {
         match self {
             GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
             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))
             }
+            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
         }
     }
 }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index e93b9eb272a..41e9a5a6651 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -332,6 +332,9 @@ impl clean::GenericArgs {
                         }
                     }
                 }
+                clean::GenericArgs::ReturnTypeNotation => {
+                    f.write_str("(..)")?;
+                }
             }
             Ok(())
         })
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 6369433a4b5..a5351b350dd 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -176,6 +176,7 @@ impl FromClean<clean::GenericArgs> for GenericArgs {
                 inputs: inputs.into_json(renderer),
                 output: output.map(|a| (*a).into_json(renderer)),
             },
+            ReturnTypeNotation => GenericArgs::ReturnTypeNotation,
         }
     }
 }
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 8ec7cffe066..44e82c7d8b1 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -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,
 /// 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.
-pub const FORMAT_VERSION: u32 = 41;
+pub const FORMAT_VERSION: u32 = 42;
 
 /// The root of the emitted JSON blob.
 ///
@@ -229,6 +229,8 @@ pub enum GenericArgs {
         /// The output type provided after the `->`, if present.
         output: Option<Type>,
     },
+    /// `T::method(..)`
+    ReturnTypeNotation,
 }
 
 /// One argument in a list of generic arguments to a path segment.
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index 791b231c27a..8c9e4c8bb3a 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -326,6 +326,7 @@ impl<'a> Validator<'a> {
                     self.check_type(o);
                 }
             }
+            GenericArgs::ReturnTypeNotation => {}
         }
     }
 
diff --git a/tests/rustdoc-json/return-type-notation.rs b/tests/rustdoc-json/return-type-notation.rs
new file mode 100644
index 00000000000..2219642bfc5
--- /dev/null
+++ b/tests/rustdoc-json/return-type-notation.rs
@@ -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,
+{
+}
diff --git a/tests/rustdoc/return-type-notation.rs b/tests/rustdoc/return-type-notation.rs
new file mode 100644
index 00000000000..405e98eb28d
--- /dev/null
+++ b/tests/rustdoc/return-type-notation.rs
@@ -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,
+{
+}