| 1 | //! A trait that can provide the `Span` of the complete contents of a syntax |
| 2 | //! tree node. |
| 3 | //! |
| 4 | //! <br> |
| 5 | //! |
| 6 | //! # Example |
| 7 | //! |
| 8 | //! Suppose in a procedural macro we have a [`Type`] that we want to assert |
| 9 | //! implements the [`Sync`] trait. Maybe this is the type of one of the fields |
| 10 | //! of a struct for which we are deriving a trait implementation, and we need to |
| 11 | //! be able to pass a reference to one of those fields across threads. |
| 12 | //! |
| 13 | //! [`Type`]: crate::Type |
| 14 | //! [`Sync`]: std::marker::Sync |
| 15 | //! |
| 16 | //! If the field type does *not* implement `Sync` as required, we want the |
| 17 | //! compiler to report an error pointing out exactly which type it was. |
| 18 | //! |
| 19 | //! The following macro code takes a variable `ty` of type `Type` and produces a |
| 20 | //! static assertion that `Sync` is implemented for that type. |
| 21 | //! |
| 22 | //! ``` |
| 23 | //! # extern crate proc_macro; |
| 24 | //! # |
| 25 | //! use proc_macro::TokenStream; |
| 26 | //! use proc_macro2::Span; |
| 27 | //! use quote::quote_spanned; |
| 28 | //! use syn::Type; |
| 29 | //! use syn::spanned::Spanned; |
| 30 | //! |
| 31 | //! # const IGNORE_TOKENS: &str = stringify! { |
| 32 | //! #[proc_macro_derive(MyMacro)] |
| 33 | //! # }; |
| 34 | //! pub fn my_macro(input: TokenStream) -> TokenStream { |
| 35 | //! # let ty = get_a_type(); |
| 36 | //! /* ... */ |
| 37 | //! |
| 38 | //! let assert_sync = quote_spanned! {ty.span()=> |
| 39 | //! struct _AssertSync where #ty: Sync; |
| 40 | //! }; |
| 41 | //! |
| 42 | //! /* ... */ |
| 43 | //! # input |
| 44 | //! } |
| 45 | //! # |
| 46 | //! # fn get_a_type() -> Type { |
| 47 | //! # unimplemented!() |
| 48 | //! # } |
| 49 | //! ``` |
| 50 | //! |
| 51 | //! By inserting this `assert_sync` fragment into the output code generated by |
| 52 | //! our macro, the user's code will fail to compile if `ty` does not implement |
| 53 | //! `Sync`. The errors they would see look like the following. |
| 54 | //! |
| 55 | //! ```text |
| 56 | //! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied |
| 57 | //! --> src/main.rs:10:21 |
| 58 | //! | |
| 59 | //! 10 | bad_field: *const i32, |
| 60 | //! | ^^^^^^^^^^ `*const i32` cannot be shared between threads safely |
| 61 | //! ``` |
| 62 | //! |
| 63 | //! In this technique, using the `Type`'s span for the error message makes the |
| 64 | //! error appear in the correct place underlining the right type. |
| 65 | //! |
| 66 | //! <br> |
| 67 | //! |
| 68 | //! # Limitations |
| 69 | //! |
| 70 | //! The underlying [`proc_macro::Span::join`] method is nightly-only. When |
| 71 | //! called from within a procedural macro in a nightly compiler, `Spanned` will |
| 72 | //! use `join` to produce the intended span. When not using a nightly compiler, |
| 73 | //! only the span of the *first token* of the syntax tree node is returned. |
| 74 | //! |
| 75 | //! In the common case of wanting to use the joined span as the span of a |
| 76 | //! `syn::Error`, consider instead using [`syn::Error::new_spanned`] which is |
| 77 | //! able to span the error correctly under the complete syntax tree node without |
| 78 | //! needing the unstable `join`. |
| 79 | //! |
| 80 | //! [`syn::Error::new_spanned`]: crate::Error::new_spanned |
| 81 | |
| 82 | use proc_macro2::Span; |
| 83 | use quote::spanned::Spanned as ToTokens; |
| 84 | |
| 85 | /// A trait that can provide the `Span` of the complete contents of a syntax |
| 86 | /// tree node. |
| 87 | /// |
| 88 | /// This trait is automatically implemented for all types that implement |
| 89 | /// [`ToTokens`] from the `quote` crate, as well as for `Span` itself. |
| 90 | /// |
| 91 | /// [`ToTokens`]: quote::ToTokens |
| 92 | /// |
| 93 | /// See the [module documentation] for an example. |
| 94 | /// |
| 95 | /// [module documentation]: self |
| 96 | pub trait Spanned: private::Sealed { |
| 97 | /// Returns a `Span` covering the complete contents of this syntax tree |
| 98 | /// node, or [`Span::call_site()`] if this node is empty. |
| 99 | /// |
| 100 | /// [`Span::call_site()`]: proc_macro2::Span::call_site |
| 101 | fn span(&self) -> Span; |
| 102 | } |
| 103 | |
| 104 | impl<T: ?Sized + ToTokens> Spanned for T { |
| 105 | fn span(&self) -> Span { |
| 106 | self.__span() |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | mod private { |
| 111 | use crate::spanned::ToTokens; |
| 112 | |
| 113 | pub trait Sealed {} |
| 114 | impl<T: ?Sized + ToTokens> Sealed for T {} |
| 115 | |
| 116 | #[cfg (any(feature = "full" , feature = "derive" ))] |
| 117 | impl Sealed for crate::QSelf {} |
| 118 | } |
| 119 | |