From 3b62b73d3b80c0f1a52aec57326af24d996caa79 Mon Sep 17 00:00:00 2001 From: Luiz Carvalho Date: Mon, 1 May 2023 22:47:11 -0300 Subject: [PATCH 1/2] chore: add deprecation notice for type ascription use --- sqlx-macros-core/src/query/args.rs | 47 ++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/sqlx-macros-core/src/query/args.rs b/sqlx-macros-core/src/query/args.rs index 71094a67d2..29d513281e 100644 --- a/sqlx-macros-core/src/query/args.rs +++ b/sqlx-macros-core/src/query/args.rs @@ -1,8 +1,8 @@ use crate::database::DatabaseExt; use crate::query::QueryMacroInput; use either::Either; -use proc_macro2::TokenStream; -use quote::{format_ident, quote, quote_spanned}; +use proc_macro2::{Ident, TokenStream}; +use quote::{format_ident, quote, quote_spanned, ToTokens}; use sqlx_core::describe::Describe; use syn::spanned::Spanned; use syn::{Expr, ExprCast, ExprGroup, ExprType, Type}; @@ -32,6 +32,8 @@ pub fn quote_args( #(let #arg_name = &(#arg_expr);)* }; + let mut args_warnings: Vec = vec![]; + let args_check = match info.parameters() { None | Some(Either::Right(_)) => { // all we can do is check arity which we did @@ -52,7 +54,12 @@ pub fn quote_args( let param_ty = match get_type_override(expr) { // cast or type ascription 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!()), + Some((ty, true)) => { + let warning = create_warning(name.clone(), ty.clone(), expr.clone()); + args_warnings.push(warning); + return Ok(quote!()) + }, None => { DB::param_type_for_id(¶m_ty) .ok_or_else(|| { @@ -101,6 +108,8 @@ pub fn quote_args( let args_count = input.arg_exprs.len(); Ok(quote! { + #(#args_warnings)* + #arg_bindings #args_check @@ -114,11 +123,37 @@ pub fn quote_args( }) } -fn get_type_override(expr: &Expr) -> Option<&Type> { +fn create_warning(name: Ident, ty: Type, expr: Expr) -> TokenStream { + let span = expr.span(); + let stripped = strip_wildcard(expr).to_token_stream(); + let current = quote!(#stripped: #ty).to_string(); + let fix = quote!(#stripped as #ty).to_string(); + + 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 +" + ); + let name = Ident::new(&format!("warning_{name}"), span); + quote_spanned!(span => + #[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, } } From 505d0fa117f20a06f2582c55f6014fbbb0538ce1 Mon Sep 17 00:00:00 2001 From: Luiz Carvalho Date: Mon, 1 May 2023 23:14:39 -0300 Subject: [PATCH 2/2] docs: type ascription deprecation --- sqlx-macros-core/src/lib.rs | 3 +-- sqlx-macros-core/src/query/args.rs | 38 ++++++++++++++---------------- sqlx-macros/Cargo.toml | 2 +- src/macros/mod.rs | 9 ++++--- 4 files changed, 26 insertions(+), 26 deletions(-) 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 29d513281e..1a5b061e8d 100644 --- a/sqlx-macros-core/src/query/args.rs +++ b/sqlx-macros-core/src/query/args.rs @@ -2,7 +2,7 @@ use crate::database::DatabaseExt; use crate::query::QueryMacroInput; use either::Either; use proc_macro2::{Ident, TokenStream}; -use quote::{format_ident, quote, quote_spanned, ToTokens}; +use quote::{format_ident, quote, quote_spanned}; use sqlx_core::describe::Describe; use syn::spanned::Spanned; use syn::{Expr, ExprCast, ExprGroup, ExprType, Type}; @@ -32,8 +32,6 @@ pub fn quote_args( #(let #arg_name = &(#arg_expr);)* }; - let mut args_warnings: Vec = vec![]; - let args_check = match info.parameters() { None | Some(Either::Right(_)) => { // all we can do is check arity which we did @@ -52,14 +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((_, false)) => return Ok(quote!()), - Some((ty, true)) => { - let warning = create_warning(name.clone(), ty.clone(), expr.clone()); - args_warnings.push(warning); - 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(|| { @@ -108,8 +103,6 @@ pub fn quote_args( let args_count = input.arg_exprs.len(); Ok(quote! { - #(#args_warnings)* - #arg_bindings #args_check @@ -123,11 +116,13 @@ pub fn quote_args( }) } -fn create_warning(name: Ident, ty: Type, expr: Expr) -> TokenStream { - let span = expr.span(); - let stripped = strip_wildcard(expr).to_token_stream(); +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!( " @@ -140,12 +135,15 @@ fn create_warning(name: Ident, ty: Type, expr: Expr) -> TokenStream { \t\tSee for more information " ); - let name = Ident::new(&format!("warning_{name}"), span); - quote_spanned!(span => - #[deprecated(note = #message)] - #[allow(non_upper_case_globals)] - const #name: () = (); - let _ = #name; + + quote_spanned!(expr.span() => + // this shouldn't actually run + if false { + #[deprecated(note = #message)] + #[allow(non_upper_case_globals)] + const #name: () = (); + let _ = #name; + } ) } 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