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