| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- // SPDX-License-Identifier: Apache-2.0 OR MIT
- //! A trait that can provide the `Span` of the complete contents of a syntax
- //! tree node.
- //!
- //! <br>
- //!
- //! # Example
- //!
- //! Suppose in a procedural macro we have a [`Type`] that we want to assert
- //! implements the [`Sync`] trait. Maybe this is the type of one of the fields
- //! of a struct for which we are deriving a trait implementation, and we need to
- //! be able to pass a reference to one of those fields across threads.
- //!
- //! [`Type`]: crate::Type
- //! [`Sync`]: std::marker::Sync
- //!
- //! If the field type does *not* implement `Sync` as required, we want the
- //! compiler to report an error pointing out exactly which type it was.
- //!
- //! The following macro code takes a variable `ty` of type `Type` and produces a
- //! static assertion that `Sync` is implemented for that type.
- //!
- //! ```
- //! # extern crate proc_macro;
- //! #
- //! use proc_macro::TokenStream;
- //! use proc_macro2::Span;
- //! use quote::quote_spanned;
- //! use syn::Type;
- //! use syn::spanned::Spanned;
- //!
- //! # const IGNORE_TOKENS: &str = stringify! {
- //! #[proc_macro_derive(MyMacro)]
- //! # };
- //! pub fn my_macro(input: TokenStream) -> TokenStream {
- //! # let ty = get_a_type();
- //! /* ... */
- //!
- //! let assert_sync = quote_spanned! {ty.span()=>
- //! struct _AssertSync where #ty: Sync;
- //! };
- //!
- //! /* ... */
- //! # input
- //! }
- //! #
- //! # fn get_a_type() -> Type {
- //! # unimplemented!()
- //! # }
- //! ```
- //!
- //! By inserting this `assert_sync` fragment into the output code generated by
- //! our macro, the user's code will fail to compile if `ty` does not implement
- //! `Sync`. The errors they would see look like the following.
- //!
- //! ```text
- //! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
- //! --> src/main.rs:10:21
- //! |
- //! 10 | bad_field: *const i32,
- //! | ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
- //! ```
- //!
- //! In this technique, using the `Type`'s span for the error message makes the
- //! error appear in the correct place underlining the right type.
- //!
- //! <br>
- //!
- //! # Limitations
- //!
- //! The underlying [`proc_macro::Span::join`] method is nightly-only. When
- //! called from within a procedural macro in a nightly compiler, `Spanned` will
- //! use `join` to produce the intended span. When not using a nightly compiler,
- //! only the span of the *first token* of the syntax tree node is returned.
- //!
- //! In the common case of wanting to use the joined span as the span of a
- //! `syn::Error`, consider instead using [`syn::Error::new_spanned`] which is
- //! able to span the error correctly under the complete syntax tree node without
- //! needing the unstable `join`.
- //!
- //! [`syn::Error::new_spanned`]: crate::Error::new_spanned
- use proc_macro2::Span;
- use quote::spanned::Spanned as ToTokens;
- /// A trait that can provide the `Span` of the complete contents of a syntax
- /// tree node.
- ///
- /// This trait is automatically implemented for all types that implement
- /// [`ToTokens`] from the `quote` crate, as well as for `Span` itself.
- ///
- /// [`ToTokens`]: quote::ToTokens
- ///
- /// See the [module documentation] for an example.
- ///
- /// [module documentation]: self
- pub trait Spanned: private::Sealed {
- /// Returns a `Span` covering the complete contents of this syntax tree
- /// node, or [`Span::call_site()`] if this node is empty.
- ///
- /// [`Span::call_site()`]: proc_macro2::Span::call_site
- fn span(&self) -> Span;
- }
- impl<T: ?Sized + ToTokens> Spanned for T {
- fn span(&self) -> Span {
- self.__span()
- }
- }
- mod private {
- use crate::spanned::ToTokens;
- pub trait Sealed {}
- impl<T: ?Sized + ToTokens> Sealed for T {}
- #[cfg(any(feature = "full", feature = "derive"))]
- impl Sealed for crate::QSelf {}
- }
|