Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow only implementing Read::read_buf #106643

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

WaffleLapkin
Copy link
Member

This PR allows users to only implement Read::read_buf, without the need for implementing Read::read. rustc_must_implement_one_of annotation ensures that at least one of the methods is implemented, so that the default impls don't create infinite recursion.

Note that Read::read_buf is unstable, so this doesn't change anything on stable, there you still need to implement Read::read, since you can't implement Read::read_buf. Thus, we don't expose rustc_must_implement_one_of to stable.

r? @thomcc

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jan 9, 2023
@rustbot
Copy link
Collaborator

rustbot commented Jan 9, 2023

Hey! It looks like you've submitted a new PR for the library teams!

If this PR contains changes to any rust-lang/rust public library APIs then please comment with @rustbot label +T-libs-api -T-libs to tag it appropriately. If this PR contains changes to any unstable APIs please edit the PR description to add a link to the relevant API Change Proposal or create one if you haven't already. If you're unsure where your change falls no worries, just leave it as is and the reviewer will take a look and make a decision to forward on if necessary.

Examples of T-libs-api changes:

  • Stabilizing library features
  • Introducing insta-stable changes such as new implementations of existing stable traits on existing stable types
  • Introducing new or changing existing unstable library APIs (excluding permanently unstable features / features without a tracking issue)
  • Changing public documentation in ways that create new stability guarantees
  • Changing observable runtime behavior of library APIs

@WaffleLapkin WaffleLapkin added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jan 9, 2023
@thomcc
Copy link
Member

thomcc commented Jan 12, 2023

For a summary:

This extends std::io::Read by allowing users to implement Read by only providing a Read::read_buf impl, and not a Read::read impl. It does this using the unstable attribute rustc_must_implement_one_of1.

#[rustc_must_implement_one_of(read, read_buf)]
pub trait std::io::Read {
    // (new)
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let mut buf = BorrowedBuf::from(buf);
        self.read_buf(buf.unfilled()).map(|()| buf.len())
    }
    // (existing)
    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
        default_read_buf(|b| self.read(b), buf)
    }
}

This does not make rustc_must_implement_must_of user-visible, since read_buf is unstable (altho IMO it could easily be forgotten when stabilizing).

Whether or not we want to start using the #[rustc_must_implement_one_of(...)] attribute on the stdlib is a question that's split between lang (if they think the language feature has a path to stabilization) and libs-api (if they are okay with using it in that case). I'm on neither of these teams, and don't feel that strongly (but weakly, I think it probably needs a t-libs-api meeting to discuss after asking t-lang if it's okay start experimenting with)

r? @joshtriplett (who is on both relevant teams)

Footnotes

  1. Which allows a trait to have a pair (or perhaps more?) of functions each of which are implemented in terms of the other, so long as the implementation user provides an impl of at least one of them for their type. I cannot seem to find a tracking method for it, but do recall discussions involving it in the past.

@rustbot rustbot assigned joshtriplett and unassigned thomcc Jan 12, 2023
@joshtriplett
Copy link
Member

I'm nominating this for T-lang to consider that question: are we OK with people using rustc_must_implement_one_of in stable standard-library APIs?

@joshtriplett joshtriplett added the I-lang-nominated Nominated for discussion during a lang team meeting. label Jan 12, 2023
@joshtriplett
Copy link
Member

Separately, I'm nominating this for libs-api. Are we OK with (on nightly) allowing people to implement read_buf and not read?

I am in favor, and in the absence of objections I'd r+ this once we have T-lang confirmation.

@joshtriplett joshtriplett added the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Jan 12, 2023
@joshtriplett
Copy link
Member

Discussed this asynchronously with some T-lang folks, and one item that came up: we'd really like to see rustc_must_implement_one_of at least documented in the Rust reference. And once it's documented, we may well be up for just stabilizing it as must_implement_one_of.

@WaffleLapkin
Copy link
Member Author

I've created a tracking issue: #107460

@joshtriplett joshtriplett removed the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Jan 31, 2023
@joshtriplett
Copy link
Member

Removing I-libs-api-nominated for now, until the attribute has documentation in the reference.

@joshtriplett
Copy link
Member

We discussed this once more in @rust-lang/lang, and confirmed that we have no objection to adding this on nightly.

@bors r+

We'd consider it a blocker for stabilization of read_buf that the attribute be either stabilized or at least documented in the reference or similar.

@bors
Copy link
Contributor

bors commented Jan 31, 2023

📌 Commit d7dac91 has been approved by joshtriplett

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 31, 2023
@dtolnay
Copy link
Member

dtolnay commented Jan 31, 2023

I am concerned about this negatively affecting the experience of non-nightly users. For example with this code:

struct MyRead;

impl std::io::Read for MyRead {}

current stable gives you this error:

error[E0046]: not all trait items implemented, missing: `read`
 --> src/main.rs:3:1
  |
3 | impl std::io::Read for MyRead {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `read` in implementation
  |
  = help: implement the missing item: `fn read(&mut self, _: &mut [u8]) -> Result<usize, std::io::Error> { todo!() }`

whereas rustc built from this PR gives this error:

error[E0046]: not all trait items implemented, missing one of: `read`, `read_buf`
   --> src/main.rs:3:1
    |
3   | impl std::io::Read for MyRead {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing one of `read`, `read_buf` in implementation
    |
note: required because of this annotation
   --> /git/rust/library/std/src/io/mod.rs:552:1
    |
552 | #[rustc_must_implement_one_of(read, read_buf)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Some concerns:

  • I only know how to build rustc in dev mode. When it's built in stable mode, is it still going to tell the user to consider implementing the unstable read_buf method, which they cannot do on a stable toolchain? That would be undesirable and it would be good to have a UI test covering this case.

  • Notice that even aside from "missing read" vs "missing one of read or read_buf", the new error is less helpful because it does not give you the signature you need to put, so there isn't a signature you can copy straight from the error into your code. Would it make sense to give 2 "help:", one with each signature?

  • How does this impact rust-analyzer? When you write a trait impl and tell it to autofill the required methods, is it going to put both? neither? just the alphanumerically first one or the one on the lower line number in libstd? My sense is a lot of people rely on this autofill when writing trait impls in an IDE.

@bors r-

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Jan 31, 2023
@joshtriplett
Copy link
Member

When it's built in stable mode, is it still going to tell the user to consider implementing the unstable read_buf method, which they cannot do on a stable toolchain? That would be undesirable and it would be good to have a UI test covering this case.

Valid; I agree that we should avoid suggesting implementing a method that you can't implement.

@WaffleLapkin, would that be feasible, and can you add a test verifying that behavior as well?

Notice that even aside from "missing read" vs "missing one of read or read_buf", the new error is less helpful because it does not give you the signature you need to put, so there isn't a signature you can copy straight from the error into your code. Would it make sense to give 2 "help:", one with each signature?

Fair. That seems like a reasonable solution for the common case.

@WaffleLapkin
Copy link
Member Author

How does this impact rust-analyzer? When you write a trait impl and tell it to autofill the required methods, is it going to put both? neither? just the alphanumerically first one or the one on the lower line number in libstd? My sense is a lot of people rely on this autofill when writing trait impls in an IDE.

@dtolnay thanks for rising these concerns! My guess is that r-a will not autofill any methods, as they all have default bodies. I'll look into how we can support this feature in r-a.

WaffleLapkin, would that be feasible, and can you add a test verifying that behavior as well?

@joshtriplett This should be feasible. I'll make a PR that removes mentions of unstable methods from this diagnostic and shows the signatures soon™.

For now, marking this PR as blocked.

@WaffleLapkin WaffleLapkin added the S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. label Feb 1, 2023
@joshtriplett joshtriplett removed the I-lang-nominated Nominated for discussion during a lang team meeting. label Feb 7, 2023
@Dylan-DPC Dylan-DPC removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 4, 2023
@dtolnay dtolnay assigned dtolnay and unassigned joshtriplett Sep 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants