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