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
span(&self) -> Span101     fn span(&self) -> Span;
102 }
103 
104 impl<T: ?Sized + ToTokens> Spanned for T {
span(&self) -> Span105     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