| 1 | //! # proc-macro-error2 |
| 2 | //! |
| 3 | //! This crate aims to make error reporting in proc-macros simple and easy to use. |
| 4 | //! Migrate from `panic!`-based errors for as little effort as possible! |
| 5 | //! |
| 6 | //! (Also, you can explicitly [append a dummy token stream](dummy/index.html) to your errors). |
| 7 | //! |
| 8 | //! To achieve his, this crate serves as a tiny shim around `proc_macro::Diagnostic` and |
| 9 | //! `compile_error!`. It detects the best way of emitting available based on compiler's version. |
| 10 | //! When the underlying diagnostic type is finally stabilized, this crate will simply be |
| 11 | //! delegating to it requiring no changes in your code! |
| 12 | //! |
| 13 | //! So you can just use this crate and have *both* some of `proc_macro::Diagnostic` functionality |
| 14 | //! available on stable ahead of time *and* your error-reporting code future-proof. |
| 15 | //! |
| 16 | //! ## Cargo features |
| 17 | //! |
| 18 | //! This crate provides *enabled by default* `syn-error` feature that gates |
| 19 | //! `impl From<syn::Error> for Diagnostic` conversion. If you don't use `syn` and want |
| 20 | //! to cut off some of compilation time, you can disable it via |
| 21 | //! |
| 22 | //! ```toml |
| 23 | //! [dependencies] |
| 24 | //! proc-macro-error2 = { version = "2.0.0", default-features = false } |
| 25 | //! ``` |
| 26 | //! |
| 27 | //! ***Please note that disabling this feature makes sense only if you don't depend on `syn` |
| 28 | //! directly or indirectly, and you very likely do.** |
| 29 | //! |
| 30 | //! ## Real world examples |
| 31 | //! |
| 32 | //! * [`structopt-derive`](https://github.com/TeXitoi/structopt/tree/master/structopt-derive) |
| 33 | //! (abort-like usage) |
| 34 | //! * [`auto-impl`](https://github.com/auto-impl-rs/auto_impl/) (emit-like usage) |
| 35 | //! |
| 36 | //! ## Limitations |
| 37 | //! |
| 38 | //! - Warnings are emitted only on nightly, they are ignored on stable. |
| 39 | //! - "help" suggestions can't have their own span info on stable, |
| 40 | //! (essentially inheriting the parent span). |
| 41 | //! - If a panic occurs somewhere in your macro no errors will be displayed. This is not a |
| 42 | //! technical limitation but rather intentional design. `panic` is not for error reporting. |
| 43 | //! |
| 44 | //! ### `#[proc_macro_error]` attribute |
| 45 | //! |
| 46 | //! **This attribute MUST be present on the top level of your macro** (the function |
| 47 | //! annotated with any of `#[proc_macro]`, `#[proc_macro_derive]`, `#[proc_macro_attribute]`). |
| 48 | //! |
| 49 | //! This attribute performs the setup and cleanup necessary to make things work. |
| 50 | //! |
| 51 | //! In most cases you'll need the simple `#[proc_macro_error]` form without any |
| 52 | //! additional settings. Feel free to [skip the "Syntax" section](#macros). |
| 53 | //! |
| 54 | //! #### Syntax |
| 55 | //! |
| 56 | //! `#[proc_macro_error]` or `#[proc_macro_error(settings...)]`, where `settings...` |
| 57 | //! is a comma-separated list of: |
| 58 | //! |
| 59 | //! - `proc_macro_hack`: |
| 60 | //! |
| 61 | //! In order to correctly cooperate with `#[proc_macro_hack]`, `#[proc_macro_error]` |
| 62 | //! attribute must be placed *before* (above) it, like this: |
| 63 | //! |
| 64 | //! ```no_run |
| 65 | //! # use proc_macro2::TokenStream; |
| 66 | //! # const IGNORE: &str = " |
| 67 | //! #[proc_macro_error] |
| 68 | //! #[proc_macro_hack] |
| 69 | //! #[proc_macro] |
| 70 | //! # " ; |
| 71 | //! fn my_macro(input: TokenStream) -> TokenStream { |
| 72 | //! unimplemented!() |
| 73 | //! } |
| 74 | //! ``` |
| 75 | //! |
| 76 | //! If, for some reason, you can't place it like that you can use |
| 77 | //! `#[proc_macro_error(proc_macro_hack)]` instead. |
| 78 | //! |
| 79 | //! # Note |
| 80 | //! |
| 81 | //! If `proc-macro-hack` was detected (by any means) `allow_not_macro` |
| 82 | //! and `assert_unwind_safe` will be applied automatically. |
| 83 | //! |
| 84 | //! - `allow_not_macro`: |
| 85 | //! |
| 86 | //! By default, the attribute checks that it's applied to a proc-macro. |
| 87 | //! If none of `#[proc_macro]`, `#[proc_macro_derive]` nor `#[proc_macro_attribute]` are |
| 88 | //! present it will panic. It's the intention - this crate is supposed to be used only with |
| 89 | //! proc-macros. |
| 90 | //! |
| 91 | //! This setting is made to bypass the check, useful in certain circumstances. |
| 92 | //! |
| 93 | //! Pay attention: the function this attribute is applied to must return |
| 94 | //! `proc_macro::TokenStream`. |
| 95 | //! |
| 96 | //! This setting is implied if `proc-macro-hack` was detected. |
| 97 | //! |
| 98 | //! - `assert_unwind_safe`: |
| 99 | //! |
| 100 | //! By default, your code must be [unwind safe]. If your code is not unwind safe, |
| 101 | //! but you believe it's correct, you can use this setting to bypass the check. |
| 102 | //! You would need this for code that uses `lazy_static` or `thread_local` with |
| 103 | //! `Cell/RefCell` inside (and the like). |
| 104 | //! |
| 105 | //! This setting is implied if `#[proc_macro_error]` is applied to a function |
| 106 | //! marked as `#[proc_macro]`, `#[proc_macro_derive]` or `#[proc_macro_attribute]`. |
| 107 | //! |
| 108 | //! This setting is also implied if `proc-macro-hack` was detected. |
| 109 | //! |
| 110 | //! ## Macros |
| 111 | //! |
| 112 | //! Most of the time you want to use the macros. Syntax is described in the next section below. |
| 113 | //! |
| 114 | //! You'll need to decide how you want to emit errors: |
| 115 | //! |
| 116 | //! * Emit the error and abort. Very much panic-like usage. Served by [`abort!`] and |
| 117 | //! [`abort_call_site!`]. |
| 118 | //! * Emit the error but do not abort right away, looking for other errors to report. |
| 119 | //! Served by [`emit_error!`] and [`emit_call_site_error!`]. |
| 120 | //! |
| 121 | //! You **can** mix these usages. |
| 122 | //! |
| 123 | //! `abort` and `emit_error` take a "source span" as the first argument. This source |
| 124 | //! will be used to highlight the place the error originates from. It must be one of: |
| 125 | //! |
| 126 | //! * *Something* that implements [`ToTokens`] (most types in `syn` and `proc-macro2` do). |
| 127 | //! This source is the preferable one since it doesn't lose span information on multi-token |
| 128 | //! spans, see [this issue](https://gitlab.com/CreepySkeleton/proc-macro-error/-/issues/6) |
| 129 | //! for details. |
| 130 | //! * [`proc_macro::Span`] |
| 131 | //! * [`proc-macro2::Span`] |
| 132 | //! |
| 133 | //! The rest is your message in format-like style. |
| 134 | //! |
| 135 | //! See [the next section](#syntax-1) for detailed syntax. |
| 136 | //! |
| 137 | //! - [`abort!`]: |
| 138 | //! |
| 139 | //! Very much panic-like usage - abort right away and show the error. |
| 140 | //! Expands to [`!`] (never type). |
| 141 | //! |
| 142 | //! - [`abort_call_site!`]: |
| 143 | //! |
| 144 | //! Shortcut for `abort!(Span::call_site(), ...)`. Expands to [`!`] (never type). |
| 145 | //! |
| 146 | //! - [`emit_error!`]: |
| 147 | //! |
| 148 | //! [`proc_macro::Diagnostic`]-like usage - emit the error but keep going, |
| 149 | //! looking for other errors to report. |
| 150 | //! The compilation will fail nonetheless. Expands to [`()`] (unit type). |
| 151 | //! |
| 152 | //! - [`emit_call_site_error!`]: |
| 153 | //! |
| 154 | //! Shortcut for `emit_error!(Span::call_site(), ...)`. Expands to [`()`] (unit type). |
| 155 | //! |
| 156 | //! - [`emit_warning!`]: |
| 157 | //! |
| 158 | //! Like `emit_error!` but emit a warning instead of error. The compilation won't fail |
| 159 | //! because of warnings. |
| 160 | //! Expands to [`()`] (unit type). |
| 161 | //! |
| 162 | //! **Beware**: warnings are nightly only, they are completely ignored on stable. |
| 163 | //! |
| 164 | //! - [`emit_call_site_warning!`]: |
| 165 | //! |
| 166 | //! Shortcut for `emit_warning!(Span::call_site(), ...)`. Expands to [`()`] (unit type). |
| 167 | //! |
| 168 | //! - [`diagnostic`]: |
| 169 | //! |
| 170 | //! Build an instance of `Diagnostic` in format-like style. |
| 171 | //! |
| 172 | //! #### Syntax |
| 173 | //! |
| 174 | //! All the macros have pretty much the same syntax: |
| 175 | //! |
| 176 | //! 1. ```ignore |
| 177 | //! abort!(single_expr) |
| 178 | //! ``` |
| 179 | //! Shortcut for `Diagnostic::from(expr).abort()`. |
| 180 | //! |
| 181 | //! 2. ```ignore |
| 182 | //! abort!(span, message) |
| 183 | //! ``` |
| 184 | //! The first argument is an expression the span info should be taken from. |
| 185 | //! |
| 186 | //! The second argument is the error message, it must implement [`ToString`]. |
| 187 | //! |
| 188 | //! 3. ```ignore |
| 189 | //! abort!(span, format_literal, format_args...) |
| 190 | //! ``` |
| 191 | //! |
| 192 | //! This form is pretty much the same as 2, except `format!(format_literal, format_args...)` |
| 193 | //! will be used to for the message instead of [`ToString`]. |
| 194 | //! |
| 195 | //! That's it. `abort!`, `emit_warning`, `emit_error` share this exact syntax. |
| 196 | //! |
| 197 | //! `abort_call_site!`, `emit_call_site_warning`, `emit_call_site_error` lack 1 form |
| 198 | //! and do not take span in 2'th and 3'th forms. Those are essentially shortcuts for |
| 199 | //! `macro!(Span::call_site(), args...)`. |
| 200 | //! |
| 201 | //! `diagnostic!` requires a [`Level`] instance between `span` and second argument |
| 202 | //! (1'th form is the same). |
| 203 | //! |
| 204 | //! > **Important!** |
| 205 | //! > |
| 206 | //! > If you have some type from `proc_macro` or `syn` to point to, do not call `.span()` |
| 207 | //! > on it but rather use it directly: |
| 208 | //! > ```no_run |
| 209 | //! > # use proc_macro_error2::abort; |
| 210 | //! > # let input = proc_macro2::TokenStream::new(); |
| 211 | //! > let ty: syn::Type = syn::parse2(input).unwrap(); |
| 212 | //! > abort!(ty, "BOOM" ); |
| 213 | //! > // ^^ <-- avoid .span() |
| 214 | //! > ``` |
| 215 | //! > |
| 216 | //! > `.span()` calls work too, but you may experience regressions in message quality. |
| 217 | //! |
| 218 | //! #### Note attachments |
| 219 | //! |
| 220 | //! 3. Every macro can have "note" attachments (only 2 and 3 form). |
| 221 | //! ```ignore |
| 222 | //! let opt_help = if have_some_info { Some("did you mean `this`?" ) } else { None }; |
| 223 | //! |
| 224 | //! abort!( |
| 225 | //! span, message; // <--- attachments start with `;` (semicolon) |
| 226 | //! |
| 227 | //! help = "format {} {}" , "arg1" , "arg2" ; // <--- every attachment ends with `;`, |
| 228 | //! // maybe except the last one |
| 229 | //! |
| 230 | //! note = "to_string" ; // <--- one arg uses `.to_string()` instead of `format!()` |
| 231 | //! |
| 232 | //! yay = "I see what {} did here" , "you" ; // <--- "help =" and "hint =" are mapped |
| 233 | //! // to Diagnostic::help, |
| 234 | //! // anything else is Diagnostic::note |
| 235 | //! |
| 236 | //! wow = note_span => "custom span" ; // <--- attachments can have their own span |
| 237 | //! // it takes effect only on nightly though |
| 238 | //! |
| 239 | //! hint =? opt_help; // <-- "optional" attachment, get displayed only if `Some` |
| 240 | //! // must be single `Option` expression |
| 241 | //! |
| 242 | //! note =? note_span => opt_help // <-- optional attachments can have custom spans too |
| 243 | //! ); |
| 244 | //! ``` |
| 245 | //! |
| 246 | |
| 247 | //! ### Diagnostic type |
| 248 | //! |
| 249 | //! [`Diagnostic`] type is intentionally designed to be API compatible with [`proc_macro::Diagnostic`]. |
| 250 | //! Not all API is implemented, only the part that can be reasonably implemented on stable. |
| 251 | //! |
| 252 | //! |
| 253 | //! [`abort!`]: macro.abort.html |
| 254 | //! [`abort_call_site!`]: macro.abort_call_site.html |
| 255 | //! [`emit_warning!`]: macro.emit_warning.html |
| 256 | //! [`emit_error!`]: macro.emit_error.html |
| 257 | //! [`emit_call_site_warning!`]: macro.emit_call_site_error.html |
| 258 | //! [`emit_call_site_error!`]: macro.emit_call_site_warning.html |
| 259 | //! [`diagnostic!`]: macro.diagnostic.html |
| 260 | //! [`Diagnostic`]: struct.Diagnostic.html |
| 261 | //! |
| 262 | //! [`proc_macro::Span`]: https://doc.rust-lang.org/proc_macro/struct.Span.html |
| 263 | //! [`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html |
| 264 | //! |
| 265 | //! [unwind safe]: https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html#what-is-unwind-safety |
| 266 | //! [`!`]: https://doc.rust-lang.org/std/primitive.never.html |
| 267 | //! [`()`]: https://doc.rust-lang.org/std/primitive.unit.html |
| 268 | //! [`ToString`]: https://doc.rust-lang.org/std/string/trait.ToString.html |
| 269 | //! |
| 270 | //! [`proc-macro2::Span`]: https://docs.rs/proc-macro2/1.0.10/proc_macro2/struct.Span.html |
| 271 | //! [`ToTokens`]: https://docs.rs/quote/1.0.3/quote/trait.ToTokens.html |
| 272 | //! |
| 273 | |
| 274 | #![cfg_attr (feature = "nightly" , feature(proc_macro_diagnostic))] |
| 275 | #![forbid (unsafe_code)] |
| 276 | |
| 277 | extern crate proc_macro; |
| 278 | |
| 279 | pub use crate::{ |
| 280 | diagnostic::{Diagnostic, DiagnosticExt, Level}, |
| 281 | dummy::{append_dummy, set_dummy}, |
| 282 | }; |
| 283 | pub use proc_macro_error_attr2::proc_macro_error; |
| 284 | |
| 285 | use proc_macro2::Span; |
| 286 | use quote::{quote, ToTokens}; |
| 287 | |
| 288 | use std::cell::Cell; |
| 289 | use std::panic::{catch_unwind, resume_unwind, UnwindSafe}; |
| 290 | |
| 291 | pub mod dummy; |
| 292 | |
| 293 | mod diagnostic; |
| 294 | mod macros; |
| 295 | mod sealed; |
| 296 | |
| 297 | #[cfg (not(feature = "nightly" ))] |
| 298 | #[path = "imp/fallback.rs" ] |
| 299 | mod imp; |
| 300 | |
| 301 | #[cfg (feature = "nightly" )] |
| 302 | #[path = "imp/delegate.rs" ] |
| 303 | mod imp; |
| 304 | |
| 305 | #[derive (Debug, Clone, Copy)] |
| 306 | #[must_use = "A SpanRange does nothing unless used" ] |
| 307 | pub struct SpanRange { |
| 308 | pub first: Span, |
| 309 | pub last: Span, |
| 310 | } |
| 311 | |
| 312 | impl SpanRange { |
| 313 | /// Create a range with the `first` and `last` spans being the same. |
| 314 | pub fn single_span(span: Span) -> Self { |
| 315 | SpanRange { |
| 316 | first: span, |
| 317 | last: span, |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | /// Create a `SpanRange` resolving at call site. |
| 322 | pub fn call_site() -> Self { |
| 323 | SpanRange::single_span(Span::call_site()) |
| 324 | } |
| 325 | |
| 326 | /// Construct span range from a `TokenStream`. This method always preserves all the |
| 327 | /// range. |
| 328 | /// |
| 329 | /// ### Note |
| 330 | /// |
| 331 | /// If the stream is empty, the result is `SpanRange::call_site()`. If the stream |
| 332 | /// consists of only one `TokenTree`, the result is `SpanRange::single_span(tt.span())` |
| 333 | /// that doesn't lose anything. |
| 334 | pub fn from_tokens(ts: &dyn ToTokens) -> Self { |
| 335 | let mut spans = ts.to_token_stream().into_iter().map(|tt| tt.span()); |
| 336 | let first = spans.next().unwrap_or_else(Span::call_site); |
| 337 | let last = spans.last().unwrap_or(first); |
| 338 | |
| 339 | SpanRange { first, last } |
| 340 | } |
| 341 | |
| 342 | /// Join two span ranges. The resulting range will start at `self.first` and end at |
| 343 | /// `other.last`. |
| 344 | pub fn join_range(self, other: SpanRange) -> Self { |
| 345 | SpanRange { |
| 346 | first: self.first, |
| 347 | last: other.last, |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | /// Collapse the range into single span, preserving as much information as possible. |
| 352 | #[must_use ] |
| 353 | pub fn collapse(self) -> Span { |
| 354 | self.first.join(self.last).unwrap_or(self.first) |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | /// This traits expands `Result<T, Into<Diagnostic>>` with some handy shortcuts. |
| 359 | pub trait ResultExt { |
| 360 | type Ok; |
| 361 | |
| 362 | /// Behaves like `Result::unwrap`: if self is `Ok` yield the contained value, |
| 363 | /// otherwise abort macro execution via `abort!`. |
| 364 | fn unwrap_or_abort(self) -> Self::Ok; |
| 365 | |
| 366 | /// Behaves like `Result::expect`: if self is `Ok` yield the contained value, |
| 367 | /// otherwise abort macro execution via `abort!`. |
| 368 | /// If it aborts then resulting error message will be preceded with `message`. |
| 369 | fn expect_or_abort(self, msg: &str) -> Self::Ok; |
| 370 | } |
| 371 | |
| 372 | /// This traits expands `Option` with some handy shortcuts. |
| 373 | pub trait OptionExt { |
| 374 | type Some; |
| 375 | |
| 376 | /// Behaves like `Option::expect`: if self is `Some` yield the contained value, |
| 377 | /// otherwise abort macro execution via `abort_call_site!`. |
| 378 | /// If it aborts the `message` will be used for [`compile_error!`][compl_err] invocation. |
| 379 | /// |
| 380 | /// [compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html |
| 381 | fn expect_or_abort(self, msg: &str) -> Self::Some; |
| 382 | } |
| 383 | |
| 384 | /// Abort macro execution and display all the emitted errors, if any. |
| 385 | /// |
| 386 | /// Does nothing if no errors were emitted (warnings do not count). |
| 387 | pub fn abort_if_dirty() { |
| 388 | imp::abort_if_dirty(); |
| 389 | } |
| 390 | |
| 391 | impl<T, E: Into<Diagnostic>> ResultExt for Result<T, E> { |
| 392 | type Ok = T; |
| 393 | |
| 394 | fn unwrap_or_abort(self) -> T { |
| 395 | match self { |
| 396 | Ok(res: T) => res, |
| 397 | Err(e: E) => e.into().abort(), |
| 398 | } |
| 399 | } |
| 400 | |
| 401 | fn expect_or_abort(self, message: &str) -> T { |
| 402 | match self { |
| 403 | Ok(res: T) => res, |
| 404 | Err(e: E) => { |
| 405 | let mut e = e.into(); |
| 406 | e.msg = format!(" {}: {}" , message, e.msg); |
| 407 | e.abort() |
| 408 | } |
| 409 | } |
| 410 | } |
| 411 | } |
| 412 | |
| 413 | impl<T> OptionExt for Option<T> { |
| 414 | type Some = T; |
| 415 | |
| 416 | fn expect_or_abort(self, message: &str) -> T { |
| 417 | match self { |
| 418 | Some(res: T) => res, |
| 419 | None => abort_call_site!(message), |
| 420 | } |
| 421 | } |
| 422 | } |
| 423 | |
| 424 | /// This is the entry point for a proc-macro. |
| 425 | /// |
| 426 | /// **NOT PUBLIC API, SUBJECT TO CHANGE WITHOUT ANY NOTICE** |
| 427 | #[doc (hidden)] |
| 428 | pub fn entry_point<F>(f: F, proc_macro_hack: bool) -> proc_macro::TokenStream |
| 429 | where |
| 430 | F: FnOnce() -> proc_macro::TokenStream + UnwindSafe, |
| 431 | { |
| 432 | ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() + 1)); |
| 433 | let caught = catch_unwind(f); |
| 434 | let dummy = dummy::cleanup(); |
| 435 | let err_storage = imp::cleanup(); |
| 436 | ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() - 1)); |
| 437 | |
| 438 | let gen_error = || { |
| 439 | if proc_macro_hack { |
| 440 | quote! {{ |
| 441 | macro_rules! proc_macro_call { |
| 442 | () => ( unimplemented!() ) |
| 443 | } |
| 444 | |
| 445 | #(#err_storage)* |
| 446 | #dummy |
| 447 | |
| 448 | unimplemented!() |
| 449 | }} |
| 450 | } else { |
| 451 | quote!( #(#err_storage)* #dummy ) |
| 452 | } |
| 453 | }; |
| 454 | |
| 455 | match caught { |
| 456 | Ok(ts) => { |
| 457 | if err_storage.is_empty() { |
| 458 | ts |
| 459 | } else { |
| 460 | gen_error().into() |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | Err(boxed) => match boxed.downcast::<AbortNow>() { |
| 465 | Ok(_) => gen_error().into(), |
| 466 | Err(boxed) => resume_unwind(boxed), |
| 467 | }, |
| 468 | } |
| 469 | } |
| 470 | |
| 471 | fn abort_now() -> ! { |
| 472 | check_correctness(); |
| 473 | std::panic::panic_any(msg:AbortNow) |
| 474 | } |
| 475 | |
| 476 | thread_local! { |
| 477 | static ENTERED_ENTRY_POINT: Cell<usize> = const { Cell::new(0) }; |
| 478 | } |
| 479 | |
| 480 | struct AbortNow; |
| 481 | |
| 482 | fn check_correctness() { |
| 483 | assert!( |
| 484 | ENTERED_ENTRY_POINT.with(Cell::get) != 0, |
| 485 | "proc-macro-error2 API cannot be used outside of `entry_point` invocation, \ |
| 486 | perhaps you forgot to annotate your #[proc_macro] function with `#[proc_macro_error]" |
| 487 | ); |
| 488 | } |
| 489 | |
| 490 | /// **ALL THE STUFF INSIDE IS NOT PUBLIC API!!!** |
| 491 | #[doc (hidden)] |
| 492 | pub mod __export { |
| 493 | // reexports for use in macros |
| 494 | pub use proc_macro; |
| 495 | pub use proc_macro2; |
| 496 | |
| 497 | use proc_macro2::Span; |
| 498 | use quote::ToTokens; |
| 499 | |
| 500 | use crate::SpanRange; |
| 501 | |
| 502 | // inspired by |
| 503 | // https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md#simple-application |
| 504 | |
| 505 | pub trait SpanAsSpanRange { |
| 506 | #[allow (non_snake_case)] |
| 507 | fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; |
| 508 | } |
| 509 | |
| 510 | pub trait Span2AsSpanRange { |
| 511 | #[allow (non_snake_case)] |
| 512 | fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; |
| 513 | } |
| 514 | |
| 515 | pub trait ToTokensAsSpanRange { |
| 516 | #[allow (non_snake_case)] |
| 517 | fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; |
| 518 | } |
| 519 | |
| 520 | pub trait SpanRangeAsSpanRange { |
| 521 | #[allow (non_snake_case)] |
| 522 | fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; |
| 523 | } |
| 524 | |
| 525 | impl<T: ToTokens> ToTokensAsSpanRange for &T { |
| 526 | fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { |
| 527 | let mut ts = self.to_token_stream().into_iter(); |
| 528 | let first = match ts.next() { |
| 529 | Some(t) => t.span(), |
| 530 | None => Span::call_site(), |
| 531 | }; |
| 532 | |
| 533 | let last = match ts.last() { |
| 534 | Some(t) => t.span(), |
| 535 | None => first, |
| 536 | }; |
| 537 | |
| 538 | SpanRange { first, last } |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | impl Span2AsSpanRange for Span { |
| 543 | fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { |
| 544 | SpanRange { |
| 545 | first: *self, |
| 546 | last: *self, |
| 547 | } |
| 548 | } |
| 549 | } |
| 550 | |
| 551 | impl SpanAsSpanRange for proc_macro::Span { |
| 552 | fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { |
| 553 | SpanRange { |
| 554 | first: (*self).into(), |
| 555 | last: (*self).into(), |
| 556 | } |
| 557 | } |
| 558 | } |
| 559 | |
| 560 | impl SpanRangeAsSpanRange for SpanRange { |
| 561 | fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { |
| 562 | *self |
| 563 | } |
| 564 | } |
| 565 | } |
| 566 | |