Skip to content

Commit a061beb

Browse files
authored
Merge pull request #383 from dtolnay/both
Support Display and Debug of same path in error message
2 parents 49be39d + 6388293 commit a061beb

File tree

2 files changed

+34
-16
lines changed

2 files changed

+34
-16
lines changed

impl/src/fmt.rs

+26-16
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::scan_expr::scan_expr;
44
use crate::unraw::{IdentUnraw, MemberUnraw};
55
use proc_macro2::{Delimiter, TokenStream, TokenTree};
66
use quote::{format_ident, quote, quote_spanned};
7-
use std::collections::{BTreeSet, HashMap, HashSet};
7+
use std::collections::{BTreeSet, HashMap};
88
use std::iter;
99
use syn::ext::IdentExt;
1010
use syn::parse::discouraged::Speculative;
@@ -34,7 +34,7 @@ impl Display<'_> {
3434
let mut infinite_recursive = false;
3535
let mut implied_bounds = BTreeSet::new();
3636
let mut bindings = Vec::new();
37-
let mut macro_named_args = HashSet::new();
37+
let mut macro_named_args = BTreeSet::new();
3838

3939
self.requires_fmt_machinery = self.requires_fmt_machinery || fmt.contains('}');
4040

@@ -85,15 +85,11 @@ impl Display<'_> {
8585
}
8686
_ => continue,
8787
};
88-
let binding_value = match &member {
89-
MemberUnraw::Unnamed(index) => format_ident!("_{}", index),
90-
MemberUnraw::Named(ident) => ident.to_local(),
91-
};
92-
let mut wrapped_binding_value = quote!(::thiserror::__private::Var(#binding_value));
9388
let end_spec = match read.find('}') {
9489
Some(end_spec) => end_spec,
9590
None => return Ok(()),
9691
};
92+
let mut bonus_display = false;
9793
let bound = match read[..end_spec].chars().next_back() {
9894
Some('?') => Trait::Debug,
9995
Some('o') => Trait::Octal,
@@ -105,10 +101,7 @@ impl Display<'_> {
105101
Some('E') => Trait::UpperExp,
106102
Some(_) => Trait::Display,
107103
None => {
108-
has_bonus_display = true;
109-
wrapped_binding_value = quote_spanned! {span=>
110-
#binding_value.as_display()
111-
};
104+
bonus_display = true;
112105
Trait::Display
113106
}
114107
};
@@ -119,19 +112,36 @@ impl Display<'_> {
119112
out += &member.to_string();
120113
continue;
121114
}
115+
let formatvar_prefix = if bonus_display {
116+
"__display"
117+
} else {
118+
"__field"
119+
};
122120
let mut formatvar = IdentUnraw::new(match &member {
123-
MemberUnraw::Unnamed(index) => format_ident!("__field{}", index),
124-
MemberUnraw::Named(ident) => format_ident!("__field_{}", ident.to_string()),
121+
MemberUnraw::Unnamed(index) => format_ident!("{}{}", formatvar_prefix, index),
122+
MemberUnraw::Named(ident) => {
123+
format_ident!("{}_{}", formatvar_prefix, ident.to_string())
124+
}
125125
});
126126
while user_named_args.contains(&formatvar) {
127127
formatvar = IdentUnraw::new(format_ident!("_{}", formatvar.to_string()));
128128
}
129129
out += &formatvar.to_string();
130-
if macro_named_args.insert(member) {
131-
bindings.push((formatvar.to_local(), wrapped_binding_value));
132-
} else {
130+
if !macro_named_args.insert(formatvar.clone()) {
133131
// Already added to bindings by a previous use.
132+
continue;
134133
}
134+
let binding_value = match &member {
135+
MemberUnraw::Unnamed(index) => format_ident!("_{}", index),
136+
MemberUnraw::Named(ident) => ident.to_local(),
137+
};
138+
let wrapped_binding_value = if bonus_display {
139+
quote_spanned!(span=> #binding_value.as_display())
140+
} else {
141+
quote!(::thiserror::__private::Var(#binding_value))
142+
};
143+
has_bonus_display |= bonus_display;
144+
bindings.push((formatvar.to_local(), wrapped_binding_value));
135145
}
136146

137147
out += read;

tests/test_path.rs

+8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ pub struct UnsizedError {
2929
pub tail: str,
3030
}
3131

32+
#[derive(Error, Debug)]
33+
pub enum BothError {
34+
#[error("display:{0} debug:{0:?}")]
35+
DisplayDebug(PathBuf),
36+
#[error("debug:{0:?} display:{0}")]
37+
DebugDisplay(PathBuf),
38+
}
39+
3240
fn assert<T: Display>(expected: &str, value: T) {
3341
assert_eq!(expected, value.to_string());
3442
}

0 commit comments

Comments
 (0)