rust-lang / rust-lang/rust

rustdoc: Consider eliminating edition sensitivity around RPIT capturing

Open
#135,453 3 comments 0 reactions 1 assignee View on GitHub

@fmease is already working on this.

Since Feb 10, 2025.

A-editions A-impl-trait C-enhancement T-rustdoc
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Uplifted from https://github.com/rust-lang/rust/issues/127228#issuecomment-2201462571 and #t-lang/blog post about precise capture (comment).


At the time of writing, rustdoc renders RPITs (return-position impl-Trait) basically identical to how they appear in the source code, most important of which is impl-Trait captures (which boils down to the presence, absence and contents of use<…> bounds for all practical purposes). Since RPIT (but not RPITIT) capturing is edition sensitive, it follows that rustdoc's RPIT rendering is edition sensitive as well. This leads us to the point of discussion: Should we (somehow) eliminate this edition sensitivity in rustdoc?

Consider the following signature as it might be shown by rustdoc: pub fn f(x: &()) -> impl Sized. Unless you know the edition of the containing crate (which could be regarded as an implementation detail?), you won't know if the RPIT impl Sized captures the anonymous lifetime of the parameter (i.e., impl Sized + use<'_>) or not (i.e., impl Sized + use<>). I believe this to be less than ideal

Edition insensitivity would solve this:

(A) The solution I initially thought of would comprise rendering synthetic use<…> bounds on use<…>-less[^1] RPITs whenever we have any[^2] generic parameters in all editions! Note: If we have anonymous lifetime parameters, we can't always easily synthesize a use<…> bound[^3].

However, this leads to more verbose output and fixates too much on pre-2024 edition behavior. Assuming the 2021 edition and before lose relevance by the minute, this solution is stuck in the past. Moreover, <2024 RPIT capturing behavior is the odd one out among RPITIT, TAIT, ATPIT (and ≥2024 RPIT).

(B) I guess the more realistic and forward-thinking solution would be to render ≥2024 RPITs as is and to always render a synthetic use<…> bounds on use<…>-less[^1] <2024 RPITs if there are any[^2] generic parameters in scope. We don't face the "anon lifetime" issues solution (A) has because the synthetic use<…> bounds should never (need to) contain any lifetime parameters! In fact, if we didn't care about non-lifetime generic parameters, we could get away with just using + use<> for ≤2021 edition crates.


I'm pretty sure this whole discussion is also relevant to rustdoc JSON (does its output even contain the edition?).

[^1]: User-written use<…> bounds are already edition agnostic/insensitive.
[^2]: I'm aware that opaque types are currently required to capture all in-scope type and const parameters (which is a temporary restriction I assume), so we could relax the rule to only consider lifetime parameters.
[^3]: Consider this Rust 2024(!) snippet: pub fn f(x: &(), y: &()) -> impl Sized. The opaque type impl Sized captures both anonymous/elided lifetime parameters. We can't denote this, use<'_> is not really an option since it's semantically ill-formed. I guess we could still use it as a sort of pseudo-Rust (rustdoc already employs pseudo-Rust syntax in certain cases). Otherwise, we could render it as pub fn f<'a, 'b>(x: &'a (), y: &'b ()) -> impl Sized + use<'a, 'b> (ensuring that 'a and 'b occur free in the signature) or pseudo-Rust pub fn f(x: &'0 (), y: &'1 ()) -> impl Sized + use<'0, '1>.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.