mirror of https://github.com/zkat/miette.git
fix(derive): allow #[label] on Option<T> when T: !Copy
This commit is contained in:
parent
df7bcfa17d
commit
62c74617d0
|
|
@ -105,6 +105,16 @@ impl Parse for LabelAttr {
|
|||
}
|
||||
}
|
||||
|
||||
/// Check if a type is syntactically `Option<...>`.
|
||||
fn is_option_type(ty: &syn::Type) -> bool {
|
||||
if let syn::Type::Path(type_path) = ty {
|
||||
if let Some(segment) = type_path.path.segments.last() {
|
||||
return segment.ident == "Option";
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
impl Labels {
|
||||
pub fn from_fields(fields: &syn::Fields) -> syn::Result<Option<Self>> {
|
||||
match fields {
|
||||
|
|
@ -185,13 +195,23 @@ impl Labels {
|
|||
quote! { miette::LabeledSpan::new_with_span }
|
||||
};
|
||||
|
||||
Some(quote! {
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&self.#span)
|
||||
.map(|#var| #ctor(
|
||||
#display,
|
||||
#var.clone(),
|
||||
))
|
||||
})
|
||||
let label_code = if is_option_type(ty) {
|
||||
quote! {
|
||||
self.#span.as_ref().map(|#var| #ctor(
|
||||
#display,
|
||||
#var.clone(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&self.#span)
|
||||
.map(|#var| #ctor(
|
||||
#display,
|
||||
#var.clone(),
|
||||
))
|
||||
}
|
||||
};
|
||||
Some(label_code)
|
||||
});
|
||||
let collections_chain = self.0.iter().filter_map(|label| {
|
||||
let Label {
|
||||
|
|
@ -272,13 +292,23 @@ impl Labels {
|
|||
quote! { miette::LabeledSpan::new_with_span }
|
||||
};
|
||||
|
||||
Some(quote! {
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(#field)
|
||||
.map(|#var| #ctor(
|
||||
#display,
|
||||
#var.clone(),
|
||||
))
|
||||
})
|
||||
let variant_label_code = if is_option_type(ty) {
|
||||
quote! {
|
||||
#field.as_ref().map(|#var| #ctor(
|
||||
#display,
|
||||
#var.clone(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(#field)
|
||||
.map(|#var| #ctor(
|
||||
#display,
|
||||
#var.clone(),
|
||||
))
|
||||
}
|
||||
};
|
||||
Some(variant_label_code)
|
||||
});
|
||||
let collections_chain = labels.0.iter().filter_map(|label| {
|
||||
let Label { span, label, ty: _, lbl_ty } = label;
|
||||
|
|
|
|||
|
|
@ -632,3 +632,39 @@ fn test_optional_source_code() {
|
|||
.source_code()
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_label_option_non_copy() {
|
||||
#[derive(Debug)]
|
||||
struct NonCopySpan(SourceSpan);
|
||||
|
||||
impl From<NonCopySpan> for SourceSpan {
|
||||
fn from(v: NonCopySpan) -> Self {
|
||||
v.0
|
||||
}
|
||||
}
|
||||
impl From<&NonCopySpan> for SourceSpan {
|
||||
fn from(v: &NonCopySpan) -> Self {
|
||||
v.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("test error")]
|
||||
struct E {
|
||||
#[source_code]
|
||||
src: String,
|
||||
#[label("here")]
|
||||
span: Option<NonCopySpan>,
|
||||
}
|
||||
|
||||
let e = E {
|
||||
src: "hello there".into(),
|
||||
span: Some(NonCopySpan((0..5).into())),
|
||||
};
|
||||
let labels: Vec<_> = e.labels().unwrap().collect();
|
||||
assert_eq!(labels.len(), 1);
|
||||
assert_eq!(labels[0].offset(), 0);
|
||||
assert_eq!(labels[0].len(), 5);
|
||||
assert_eq!(labels[0].label(), Some("here"));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue