From 3eb19542933e0519e34d0c80ac07f30228e910e3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 13 Mar 2023 10:13:48 -0700 Subject: [PATCH] Help span argument of quote_spanned get inferred to Span --- src/lib.rs | 10 +++++----- src/runtime.rs | 31 ++++++++++++++++++++++--------- tests/test.rs | 31 ++++++++++++++++++++++++++++++- tests/ui/ambiguous-span.rs | 16 ---------------- tests/ui/ambiguous-span.stderr | 13 ------------- tests/ui/wrong-type-span.stderr | 15 ++++++--------- 6 files changed, 63 insertions(+), 53 deletions(-) delete mode 100644 tests/ui/ambiguous-span.rs delete mode 100644 tests/ui/ambiguous-span.stderr diff --git a/src/lib.rs b/src/lib.rs index 68bb085..8b6afa2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -619,14 +619,14 @@ macro_rules! quote_spanned { #[macro_export] macro_rules! quote_spanned { ($span:expr=>) => {{ - let _ = $crate::__private::IntoSpan::into_span($span); + let _ = $crate::__private::GetSpan($span).__into_span(); $crate::__private::TokenStream::new() }}; // Special case rule for a single tt, for performance. ($span:expr=> $tt:tt) => {{ let mut _s = $crate::__private::TokenStream::new(); - let _span = $crate::__private::IntoSpan::into_span($span); + let _span = $crate::__private::GetSpan($span).__into_span(); $crate::quote_token_spanned!{$tt _s _span} _s }}; @@ -634,13 +634,13 @@ macro_rules! quote_spanned { // Special case rules for two tts, for performance. ($span:expr=> # $var:ident) => {{ let mut _s = $crate::__private::TokenStream::new(); - let _ = $crate::__private::IntoSpan::into_span($span); + let _ = $crate::__private::GetSpan($span).__into_span(); $crate::ToTokens::to_tokens(&$var, &mut _s); _s }}; ($span:expr=> $tt1:tt $tt2:tt) => {{ let mut _s = $crate::__private::TokenStream::new(); - let _span = $crate::__private::IntoSpan::into_span($span); + let _span = $crate::__private::GetSpan($span).__into_span(); $crate::quote_token_spanned!{$tt1 _s _span} $crate::quote_token_spanned!{$tt2 _s _span} _s @@ -649,7 +649,7 @@ macro_rules! quote_spanned { // Rule for any other number of tokens. ($span:expr=> $($tt:tt)*) => {{ let mut _s = $crate::__private::TokenStream::new(); - let _span = $crate::__private::IntoSpan::into_span($span); + let _span = $crate::__private::GetSpan($span).__into_span(); $crate::quote_each_token_spanned!{_s _span $($tt)*} _s }}; diff --git a/src/runtime.rs b/src/runtime.rs index c94e082..3861395 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,7 +1,7 @@ use crate::{IdentFragment, ToTokens, TokenStreamExt}; use core::fmt; use core::iter; -use core::ops::BitOr; +use core::ops::{BitOr, Deref}; use proc_macro2::extra::DelimSpan; use proc_macro2::{Group, Ident, Punct, Spacing, TokenTree}; @@ -166,21 +166,34 @@ impl ToTokens for RepInterp { } } -pub trait IntoSpan { - fn into_span(self) -> Span; +#[repr(transparent)] +pub struct GetSpan(pub T); + +#[repr(transparent)] +pub struct WrapperDelimSpan { + span: DelimSpan, +} + +impl GetSpan { + #[inline] + pub fn __into_span(self) -> Span { + self.0 + } } -impl IntoSpan for Span { +impl WrapperDelimSpan { #[inline] - fn into_span(self) -> Span { - self + pub fn __into_span(&self) -> Span { + self.span.join() } } -impl IntoSpan for DelimSpan { +impl Deref for GetSpan { + type Target = WrapperDelimSpan; + #[inline] - fn into_span(self) -> Span { - self.join() + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const GetSpan as *const WrapperDelimSpan) } } } diff --git a/tests/test.rs b/tests/test.rs index 41eba51..eab4f55 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -6,10 +6,12 @@ clippy::used_underscore_binding )] +extern crate proc_macro; + use std::borrow::Cow; use std::collections::BTreeSet; -use proc_macro2::{Ident, Span, TokenStream}; +use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned, TokenStreamExt}; struct X; @@ -518,3 +520,30 @@ fn test_quote_raw_id() { let id = quote!(r#raw_id); assert_eq!(id.to_string(), "r#raw_id"); } + +#[test] +fn test_type_inference_for_span() { + trait CallSite { + fn get() -> Self; + } + + impl CallSite for Span { + fn get() -> Self { + Span::call_site() + } + } + + let span = Span::call_site(); + let _ = quote_spanned!(span=> ...); + + let delim_span = Group::new(Delimiter::Parenthesis, TokenStream::new()).delim_span(); + let _ = quote_spanned!(delim_span=> ...); + + let inferred = CallSite::get(); + let _ = quote_spanned!(inferred=> ...); + + if false { + let proc_macro_span = proc_macro::Span::call_site(); + let _ = quote_spanned!(proc_macro_span.into()=> ...); + } +} diff --git a/tests/ui/ambiguous-span.rs b/tests/ui/ambiguous-span.rs deleted file mode 100644 index 4582dc8..0000000 --- a/tests/ui/ambiguous-span.rs +++ /dev/null @@ -1,16 +0,0 @@ -use proc_macro2::Span; -use quote::quote_spanned; - -trait CallSite { - fn get() -> Self; -} - -impl CallSite for Span { - fn get() -> Self { - Span::call_site() - } -} - -fn main() { - let _ = quote_spanned!(CallSite::get()=> ...); -} diff --git a/tests/ui/ambiguous-span.stderr b/tests/ui/ambiguous-span.stderr deleted file mode 100644 index 3433df5..0000000 --- a/tests/ui/ambiguous-span.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0283]: type annotations needed - --> tests/ui/ambiguous-span.rs:15:28 - | -15 | let _ = quote_spanned!(CallSite::get()=> ...); - | ---------------^^^^^^^^^^^^^^^------- - | | | - | | cannot infer type - | required by a bound introduced by this call - | - = note: cannot satisfy `_: IntoSpan` - = help: the following types implement trait `IntoSpan`: - DelimSpan - Span diff --git a/tests/ui/wrong-type-span.stderr b/tests/ui/wrong-type-span.stderr index 6192067..5061c60 100644 --- a/tests/ui/wrong-type-span.stderr +++ b/tests/ui/wrong-type-span.stderr @@ -1,12 +1,9 @@ -error[E0277]: the trait bound `&str: IntoSpan` is not satisfied - --> tests/ui/wrong-type-span.rs:6:20 +error[E0599]: no method named `__into_span` found for struct `GetSpan<&str>` in the current scope + --> tests/ui/wrong-type-span.rs:6:5 | 6 | quote_spanned!(span=> #x); - | ---------------^^^^------ - | | | - | | the trait `IntoSpan` is not implemented for `&str` - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `GetSpan<&str>` | - = help: the following other types implement trait `IntoSpan`: - Span - proc_macro2::extra::DelimSpan + = note: the method was found for + - `GetSpan` + = note: this error originates in the macro `quote_spanned` (in Nightly builds, run with -Z macro-backtrace for more info)