From dc12bd09aa53ddab7b686786ed8fac1d060d37c4 Mon Sep 17 00:00:00 2001 From: Tim Kuehn Date: Sun, 5 Jun 2022 15:23:35 -0700 Subject: [PATCH] Annotate types that impl Future with #[must_use]. These types do nothing unless polled / .awaited. Annotating them with #[must_use] helps prevent a common class of coding errors. Fixes https://github.com/google/tarpc/issues/368. --- tarpc/src/client.rs | 1 + tarpc/src/serde_transport.rs | 1 + tarpc/src/server/tokio.rs | 2 ++ tarpc/tests/compile_fail.rs | 4 +++ .../compile_fail/must_use_request_dispatch.rs | 15 ++++++++++ .../must_use_request_dispatch.stderr | 11 +++++++ .../serde_transport/must_use_tcp_connect.rs | 9 ++++++ .../must_use_tcp_connect.stderr | 11 +++++++ .../tokio/must_use_channel_executor.rs | 29 ++++++++++++++++++ .../tokio/must_use_channel_executor.stderr | 11 +++++++ .../tokio/must_use_server_executor.rs | 30 +++++++++++++++++++ .../tokio/must_use_server_executor.stderr | 11 +++++++ 12 files changed, 135 insertions(+) create mode 100644 tarpc/tests/compile_fail/must_use_request_dispatch.rs create mode 100644 tarpc/tests/compile_fail/must_use_request_dispatch.stderr create mode 100644 tarpc/tests/compile_fail/serde_transport/must_use_tcp_connect.rs create mode 100644 tarpc/tests/compile_fail/serde_transport/must_use_tcp_connect.stderr create mode 100644 tarpc/tests/compile_fail/tokio/must_use_channel_executor.rs create mode 100644 tarpc/tests/compile_fail/tokio/must_use_channel_executor.stderr create mode 100644 tarpc/tests/compile_fail/tokio/must_use_server_executor.rs create mode 100644 tarpc/tests/compile_fail/tokio/must_use_server_executor.stderr diff --git a/tarpc/src/client.rs b/tarpc/src/client.rs index 44ae909..f2bae32 100644 --- a/tarpc/src/client.rs +++ b/tarpc/src/client.rs @@ -255,6 +255,7 @@ where /// Handles the lifecycle of requests, writing requests to the wire, managing cancellations, /// and dispatching responses to the appropriate channel. +#[must_use] #[pin_project] #[derive(Debug)] pub struct RequestDispatch { diff --git a/tarpc/src/serde_transport.rs b/tarpc/src/serde_transport.rs index aae63a0..aaddc36 100644 --- a/tarpc/src/serde_transport.rs +++ b/tarpc/src/serde_transport.rs @@ -149,6 +149,7 @@ pub mod tcp { } /// A connection Future that also exposes the length-delimited framing config. + #[must_use] #[pin_project] pub struct Connect { #[pin] diff --git a/tarpc/src/server/tokio.rs b/tarpc/src/server/tokio.rs index 87db4c2..a44e846 100644 --- a/tarpc/src/server/tokio.rs +++ b/tarpc/src/server/tokio.rs @@ -6,6 +6,7 @@ use std::pin::Pin; /// A future that drives the server by [spawning](tokio::spawn) a [`TokioChannelExecutor`](TokioChannelExecutor) /// for each new channel. Returned by /// [`Incoming::execute`](crate::server::incoming::Incoming::execute). +#[must_use] #[pin_project] #[derive(Debug)] pub struct TokioServerExecutor { @@ -23,6 +24,7 @@ impl TokioServerExecutor { /// A future that drives the server by [spawning](tokio::spawn) each [response /// handler](super::InFlightRequest::execute) on tokio's default executor. Returned by /// [`Channel::execute`](crate::server::Channel::execute). +#[must_use] #[pin_project] #[derive(Debug)] pub struct TokioChannelExecutor { diff --git a/tarpc/tests/compile_fail.rs b/tarpc/tests/compile_fail.rs index 8f897c3..4c5a28e 100644 --- a/tarpc/tests/compile_fail.rs +++ b/tarpc/tests/compile_fail.rs @@ -2,4 +2,8 @@ fn ui() { let t = trybuild::TestCases::new(); t.compile_fail("tests/compile_fail/*.rs"); + #[cfg(feature = "tokio1")] + t.compile_fail("tests/compile_fail/tokio/*.rs"); + #[cfg(all(feature = "serde-transport", feature = "tcp"))] + t.compile_fail("tests/compile_fail/serde_transport/*.rs"); } diff --git a/tarpc/tests/compile_fail/must_use_request_dispatch.rs b/tarpc/tests/compile_fail/must_use_request_dispatch.rs new file mode 100644 index 0000000..2915d32 --- /dev/null +++ b/tarpc/tests/compile_fail/must_use_request_dispatch.rs @@ -0,0 +1,15 @@ +use tarpc::client; + +#[tarpc::service] +trait World { + async fn hello(name: String) -> String; +} + +fn main() { + let (client_transport, _) = tarpc::transport::channel::unbounded(); + + #[deny(unused_must_use)] + { + WorldClient::new(client::Config::default(), client_transport).dispatch; + } +} diff --git a/tarpc/tests/compile_fail/must_use_request_dispatch.stderr b/tarpc/tests/compile_fail/must_use_request_dispatch.stderr new file mode 100644 index 0000000..823ac5b --- /dev/null +++ b/tarpc/tests/compile_fail/must_use_request_dispatch.stderr @@ -0,0 +1,11 @@ +error: unused `RequestDispatch` that must be used + --> tests/compile_fail/must_use_request_dispatch.rs:13:9 + | +13 | WorldClient::new(client::Config::default(), client_transport).dispatch; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/compile_fail/must_use_request_dispatch.rs:11:12 + | +11 | #[deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ diff --git a/tarpc/tests/compile_fail/serde_transport/must_use_tcp_connect.rs b/tarpc/tests/compile_fail/serde_transport/must_use_tcp_connect.rs new file mode 100644 index 0000000..1f437b1 --- /dev/null +++ b/tarpc/tests/compile_fail/serde_transport/must_use_tcp_connect.rs @@ -0,0 +1,9 @@ +use tarpc::serde_transport; +use tokio_serde::formats::Json; + +fn main() { + #[deny(unused_must_use)] + { + serde_transport::tcp::connect::<_, (), (), _, _>("0.0.0.0:0", Json::default); + } +} diff --git a/tarpc/tests/compile_fail/serde_transport/must_use_tcp_connect.stderr b/tarpc/tests/compile_fail/serde_transport/must_use_tcp_connect.stderr new file mode 100644 index 0000000..e668e80 --- /dev/null +++ b/tarpc/tests/compile_fail/serde_transport/must_use_tcp_connect.stderr @@ -0,0 +1,11 @@ +error: unused `Connect` that must be used + --> tests/compile_fail/serde_transport/must_use_tcp_connect.rs:7:9 + | +7 | serde_transport::tcp::connect::<_, (), (), _, _>("0.0.0.0:0", Json::default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/compile_fail/serde_transport/must_use_tcp_connect.rs:5:12 + | +5 | #[deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ diff --git a/tarpc/tests/compile_fail/tokio/must_use_channel_executor.rs b/tarpc/tests/compile_fail/tokio/must_use_channel_executor.rs new file mode 100644 index 0000000..6fc2f2b --- /dev/null +++ b/tarpc/tests/compile_fail/tokio/must_use_channel_executor.rs @@ -0,0 +1,29 @@ +use tarpc::{ + context, + server::{self, Channel}, +}; + +#[tarpc::service] +trait World { + async fn hello(name: String) -> String; +} + +#[derive(Clone)] +struct HelloServer; + +#[tarpc::server] +impl World for HelloServer { + async fn hello(self, _: context::Context, name: String) -> String { + format!("Hello, {name}!") + } +} + +fn main() { + let (_, server_transport) = tarpc::transport::channel::unbounded(); + let server = server::BaseChannel::with_defaults(server_transport); + + #[deny(unused_must_use)] + { + server.execute(HelloServer.serve()); + } +} diff --git a/tarpc/tests/compile_fail/tokio/must_use_channel_executor.stderr b/tarpc/tests/compile_fail/tokio/must_use_channel_executor.stderr new file mode 100644 index 0000000..5b5adf0 --- /dev/null +++ b/tarpc/tests/compile_fail/tokio/must_use_channel_executor.stderr @@ -0,0 +1,11 @@ +error: unused `TokioChannelExecutor` that must be used + --> tests/compile_fail/tokio/must_use_channel_executor.rs:27:9 + | +27 | server.execute(HelloServer.serve()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/compile_fail/tokio/must_use_channel_executor.rs:25:12 + | +25 | #[deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ diff --git a/tarpc/tests/compile_fail/tokio/must_use_server_executor.rs b/tarpc/tests/compile_fail/tokio/must_use_server_executor.rs new file mode 100644 index 0000000..950cf74 --- /dev/null +++ b/tarpc/tests/compile_fail/tokio/must_use_server_executor.rs @@ -0,0 +1,30 @@ +use futures::stream::once; +use tarpc::{ + context, + server::{self, incoming::Incoming}, +}; + +#[tarpc::service] +trait World { + async fn hello(name: String) -> String; +} + +#[derive(Clone)] +struct HelloServer; + +#[tarpc::server] +impl World for HelloServer { + async fn hello(self, _: context::Context, name: String) -> String { + format!("Hello, {name}!") + } +} + +fn main() { + let (_, server_transport) = tarpc::transport::channel::unbounded(); + let server = once(async move { server::BaseChannel::with_defaults(server_transport) }); + + #[deny(unused_must_use)] + { + server.execute(HelloServer.serve()); + } +} diff --git a/tarpc/tests/compile_fail/tokio/must_use_server_executor.stderr b/tarpc/tests/compile_fail/tokio/must_use_server_executor.stderr new file mode 100644 index 0000000..57daf90 --- /dev/null +++ b/tarpc/tests/compile_fail/tokio/must_use_server_executor.stderr @@ -0,0 +1,11 @@ +error: unused `TokioServerExecutor` that must be used + --> tests/compile_fail/tokio/must_use_server_executor.rs:28:9 + | +28 | server.execute(HelloServer.serve()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/compile_fail/tokio/must_use_server_executor.rs:26:12 + | +26 | #[deny(unused_must_use)] + | ^^^^^^^^^^^^^^^