From ae5626ca2ca6fd26d4ef56e7f1a5f68e4124fc19 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 8 Nov 2024 11:59:27 -0500 Subject: [PATCH] Wrap interpolated variables to forward Pointer correctly --- impl/src/fmt.rs | 13 ++++++----- src/lib.rs | 3 +++ src/var.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 src/var.rs diff --git a/impl/src/fmt.rs b/impl/src/fmt.rs index d369012..e69a7e9 100644 --- a/impl/src/fmt.rs +++ b/impl/src/fmt.rs @@ -3,7 +3,7 @@ use crate::attr::{Display, Trait}; use crate::scan_expr::scan_expr; use crate::unraw::{IdentUnraw, MemberUnraw}; use proc_macro2::{Delimiter, TokenStream}; -use quote::{format_ident, quote, quote_spanned, ToTokens}; +use quote::{format_ident, quote, quote_spanned}; use std::collections::{BTreeSet, HashMap, HashSet}; use std::iter; use syn::ext::IdentExt; @@ -85,10 +85,11 @@ impl Display<'_> { } _ => continue, }; - let mut binding_value = ToTokens::into_token_stream(match &member { + let binding_value = match &member { MemberUnraw::Unnamed(index) => format_ident!("_{}", index), MemberUnraw::Named(ident) => ident.to_local(), - }); + }; + let mut wrapped_binding_value = quote!(::thiserror::__private::Var(#binding_value)); let end_spec = match read.find('}') { Some(end_spec) => end_spec, None => return Ok(()), @@ -105,7 +106,9 @@ impl Display<'_> { Some(_) => Trait::Display, None => { has_bonus_display = true; - binding_value.extend(quote_spanned!(span=> .as_display())); + wrapped_binding_value = quote_spanned! {span=> + #binding_value.as_display() + }; Trait::Display } }; @@ -126,7 +129,7 @@ impl Display<'_> { out += &formatvar.to_string(); let local = formatvar.to_local(); if macro_named_args.insert(member) { - bindings.push((local, binding_value)); + bindings.push((local, wrapped_binding_value)); } else { // Already added to bindings by a previous use. } diff --git a/src/lib.rs b/src/lib.rs index 1489fc6..ea5244d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -280,6 +280,7 @@ mod aserror; mod display; #[cfg(error_generic_member_access)] mod provide; +mod var; pub use thiserror_impl::*; @@ -294,6 +295,8 @@ pub mod __private { #[doc(hidden)] pub use crate::provide::ThiserrorProvide; #[doc(hidden)] + pub use crate::var::Var; + #[doc(hidden)] pub use core::error::Error; #[cfg(all(feature = "std", not(thiserror_no_backtrace_type)))] #[doc(hidden)] diff --git a/src/var.rs b/src/var.rs new file mode 100644 index 0000000..e0b9bb5 --- /dev/null +++ b/src/var.rs @@ -0,0 +1,59 @@ +use core::fmt::{ + self, Binary, Debug, Display, LowerExp, LowerHex, Octal, Pointer, UpperExp, UpperHex, +}; + +pub struct Var<'a, T: ?Sized>(pub &'a T); + +impl<'a, T: Pointer + ?Sized> Pointer for Var<'a, T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Pointer::fmt(self.0, formatter) + } +} + +impl<'a, T: Binary + ?Sized> Binary for Var<'a, T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Binary::fmt(self.0, formatter) + } +} + +impl<'a, T: Debug + ?Sized> Debug for Var<'a, T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(self.0, formatter) + } +} + +impl<'a, T: Display + ?Sized> Display for Var<'a, T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self.0, formatter) + } +} + +impl<'a, T: LowerExp + ?Sized> LowerExp for Var<'a, T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + LowerExp::fmt(self.0, formatter) + } +} + +impl<'a, T: LowerHex + ?Sized> LowerHex for Var<'a, T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + LowerHex::fmt(self.0, formatter) + } +} + +impl<'a, T: Octal + ?Sized> Octal for Var<'a, T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Octal::fmt(self.0, formatter) + } +} + +impl<'a, T: UpperExp + ?Sized> UpperExp for Var<'a, T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + UpperExp::fmt(self.0, formatter) + } +} + +impl<'a, T: UpperHex + ?Sized> UpperHex for Var<'a, T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + UpperHex::fmt(self.0, formatter) + } +}