Skip to main content

syn/
spanned.rs

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
84use proc_macro2::Span;
85use 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
98pub 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
106impl<T: ?Sized + ToTokens> Spanned for T {
107    fn span(&self) -> Span {
108        self.__span()
109    }
110}
111
112mod 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}