I am quite new to Rust and I stumbled upon this warning from Clippy in my codebase:
warning: docs for function which may panic missing `# Panics` section
--> src/activity.rs:113:1 ▐
| ▐
113 | pub async fn running(db: &PgPool, user_id: String) -> anyhow::Result<Option<Running>> { ▐
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ▐
|
note: first possible panic found here
--> src/activity.rs:130:9
|
130 | user_id
| ^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc
= note: `-W clippy::missing-panics-doc` implied by `-W clippy::pedantic`
= help: to override `-W clippy::pedantic` add `#[allow(clippy::missing_panics_doc)]`
The connected code looks like this:
#[derive(Debug)]
pub struct Running {
id: sqlx::types::Uuid,
user_id: String,
name: String,
start_time: chrono::DateTime<chrono::Utc>,
end_time: Option<chrono::DateTime<chrono::Utc>>,
tags: Vec<Tag>,
}
pub async fn running(db: &PgPool, user_id: String) -> anyhow::Result<Option<Running>> {
let result = sqlx::query_as!(
Running,
r#"
SELECT
activities.*,
COALESCE(array_agg((tags.id, tags.user_id, tags.name)) filter (WHERE tags.id IS NOT NULL), '{}') AS "tags!: Vec<Tag>"
FROM activities
LEFT JOIN activities_tags
ON activities.id = activities_tags.activity_id
LEFT JOIN tags
ON activities_tags.tag_id = tags.id
WHERE activities.user_id = $1 AND end_time IS NULL
GROUP BY activities.id
ORDER BY activities.start_time ASC
LIMIT 1
"#,
user_id
).fetch_optional(db).await?;
Ok(result)
}
I dug through the internet with this warning, but could not really find an answer or solution.
I am wondering two things:
sqlx
for example?My thought process so far in Rust was that when it compiles you are pretty much good to go, but this warning makes me wonder, if there is still some run-time magic going on which have to be aware of?
I would like to shed some light on your issue. I stumbled upon the same issue today and I think I know the cause.
The macro query_as!
expands into something that contains panic.
If you follow how the macro expands you will find that for each parameter ($1
, user_id
in your case) of the query, the expanded macro contains this piece of code (link to github here):
// this shouldn't actually run
if false {
use ::sqlx::ty_match::{WrapSameExt as _, MatchBorrowExt as _};
// evaluate the expression only once in case it contains moves
let expr = ::sqlx::ty_match::dupe_value(#name);
// if `expr` is `Option<T>`, get `Option<$ty>`, otherwise `$ty`
let ty_check = ::sqlx::ty_match::WrapSame::<#param_ty, _>::new(&expr).wrap_same();
// if `expr` is `&str`, convert `String` to `&str`
let (mut _ty_check, match_borrow) = ::sqlx::ty_match::MatchBorrow::new(ty_check, &expr);
_ty_check = match_borrow.match_borrow();
// this causes move-analysis to effectively ignore this block
::std::panic!();
}
Clippy then thinks this panic can happen, when in reality it can't.
Interesting is that authors of the library thought about clippy. At the start of the expanded macro is #[allow(clippy::all)]
(link to github here). But for some reason it doesn't allow panics.
Probably not needed anymore but anyway, my advice is to use #[allow(clippy::panic)]
before each query. Or you can put it on module which contains your queries.