diff --git a/sqlx-macros-core/src/lib.rs b/sqlx-macros-core/src/lib.rs index dafb2ca012..0c11d57bba 100644 --- a/sqlx-macros-core/src/lib.rs +++ b/sqlx-macros-core/src/lib.rs @@ -19,8 +19,6 @@ feature(track_path) )] -use once_cell::sync::Lazy; - use crate::query::QueryDriver; pub type Error = Box; @@ -54,6 +52,7 @@ where { #[cfg(feature = "_rt-tokio")] { + use once_cell::sync::Lazy; use tokio::runtime::{self, Runtime}; // We need a single, persistent Tokio runtime since we're caching connections, diff --git a/sqlx-macros-core/src/query/args.rs b/sqlx-macros-core/src/query/args.rs index 71094a67d2..1a5b061e8d 100644 --- a/sqlx-macros-core/src/query/args.rs +++ b/sqlx-macros-core/src/query/args.rs @@ -1,7 +1,7 @@ use crate::database::DatabaseExt; use crate::query::QueryMacroInput; use either::Either; -use proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, quote_spanned}; use sqlx_core::describe::Describe; use syn::spanned::Spanned; @@ -50,9 +50,11 @@ pub fn quote_args( .enumerate() .map(|(i, (param_ty, (name, expr)))| -> crate::Result<_> { let param_ty = match get_type_override(expr) { - // cast or type ascription will fail to compile if the type does not match + // cast will fail to compile if the type does not match // and we strip casts to wildcard - Some(_) => return Ok(quote!()), + Some((_, false)) => return Ok(quote!()), + // type ascription is deprecated + Some((ty, true)) => return Ok(create_warning(name.clone(), &ty, &expr)), None => { DB::param_type_for_id(¶m_ty) .ok_or_else(|| { @@ -114,11 +116,42 @@ pub fn quote_args( }) } -fn get_type_override(expr: &Expr) -> Option<&Type> { +fn create_warning(name: Ident, ty: &Type, expr: &Expr) -> TokenStream { + let Expr::Type(ExprType { expr: stripped, .. }) = expr else { + return quote!(); + }; + let current = quote!(#stripped: #ty).to_string(); + let fix = quote!(#stripped as #ty).to_string(); + let name = Ident::new(&format!("warning_{name}"), expr.span()); + + let message = format!( + " +\t\tType ascription pattern is deprecated, prefer casting +\t\tTry changing from +\t\t\t`{current}` +\t\tto +\t\t\t`{fix}` + +\t\tSee for more information +" + ); + + quote_spanned!(expr.span() => + // this shouldn't actually run + if false { + #[deprecated(note = #message)] + #[allow(non_upper_case_globals)] + const #name: () = (); + let _ = #name; + } + ) +} + +fn get_type_override(expr: &Expr) -> Option<(&Type, bool)> { match expr { Expr::Group(group) => get_type_override(&group.expr), - Expr::Cast(cast) => Some(&cast.ty), - Expr::Type(ascription) => Some(&ascription.ty), + Expr::Cast(cast) => Some((&cast.ty, false)), + Expr::Type(ascription) => Some((&ascription.ty, true)), _ => None, } } diff --git a/sqlx-macros/Cargo.toml b/sqlx-macros/Cargo.toml index f545a186d7..f96e6f84d7 100644 --- a/sqlx-macros/Cargo.toml +++ b/sqlx-macros/Cargo.toml @@ -43,5 +43,5 @@ sqlx-core = { workspace = true, default-features = false, features = ["any"] } sqlx-macros-core = { workspace = true } proc-macro2 = { version = "1.0.36", default-features = false } -syn = { version = "1.0.84", default-features = false, features = ["full"] } +syn = { version = "1.0.84", default-features = false, features = ["parsing", "proc-macro"] } quote = { version = "1.0.14", default-features = false } diff --git a/src/macros/mod.rs b/src/macros/mod.rs index 379fe41e4a..71e7696778 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -151,9 +151,12 @@ /// sqlx::query!("select $1::int4 as id", my_int as MyInt4) /// ``` /// -/// Using `expr as _` or `expr : _` simply signals to the macro to not type-check that bind expression, -/// and then that syntax is stripped from the expression so as to not trigger type errors -/// (or an unstable syntax feature in the case of the latter, which is called type ascription). +/// Using `expr as _` simply signals to the macro to not type-check that bind expression, +/// and then that syntax is stripped from the expression so as to not trigger type errors. +/// +/// **NOTE:** type ascription syntax (`expr: _`) is deprecated and will be removed in a +/// future release. This is due to Rust's [RFC 3307](https://github.com/rust-lang/rfcs/pull/3307) +/// officially dropping support for the syntax. /// /// ## Type Overrides: Output Columns /// Type overrides are also available for output columns, utilizing the SQL standard's support