fix(tvix/nix-compat-derive): Better errors for default

This adds a span to default handling so that any error message
gives a more precise location as a hint for why the error occurred
instead of just pointing to the type.

Change-Id: I7bf6cf38e0284f9726d670ea50a94a6b1edd8a94
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12728
Reviewed-by: Vladimir Kryachko <v.kryachko@gmail.com>
Reviewed-by: flokli <flokli@flokli.de>
Tested-by: BuildkiteCI
Autosubmit: Brian Olsen <me@griff.name>
This commit is contained in:
Brian Olsen 2024-11-03 20:37:08 +01:00 committed by clbot
parent cae3afc758
commit 6582fa69f1
2 changed files with 13 additions and 7 deletions

View file

@ -111,7 +111,9 @@ fn nix_deserialize_struct(style: Style, fields: &[Field<'_>]) -> TokenStream {
};
if let Some(version) = f.attrs.version.as_ref() {
let default = match &f.attrs.default {
Default::Default => quote_spanned!(ty.span()=>::std::default::Default::default),
Default::Default(span) => {
quote_spanned!(span.span()=>::std::default::Default::default)
}
Default::Path(path) => path.to_token_stream(),
_ => panic!("No default for versioned field"),
};
@ -172,7 +174,9 @@ fn nix_deserialize_variant(variant: &Variant<'_>) -> TokenStream {
};
if let Some(version) = f.attrs.version.as_ref() {
let default = match &f.attrs.default {
Default::Default => quote_spanned!(ty.span()=>::std::default::Default::default),
Default::Default(span) => {
quote_spanned!(span.span()=>::std::default::Default::default)
}
Default::Path(path) => path.to_token_stream(),
_ => panic!("No default for versioned field"),
};

View file

@ -10,7 +10,7 @@ use super::Context;
pub enum Default {
None,
#[allow(clippy::enum_variant_names)]
Default,
Default(syn::Path),
Path(ExprPath),
}
@ -29,6 +29,7 @@ pub struct Field {
impl Field {
pub fn from_ast(ctx: &Context, attrs: &Vec<Attribute>) -> Field {
let mut version = None;
let mut version_path = None;
let mut default = Default::None;
for attr in attrs {
if attr.path() != NIX {
@ -37,13 +38,14 @@ impl Field {
if let Err(err) = attr.parse_nested_meta(|meta| {
if meta.path == VERSION {
version = parse_lit(ctx, &meta, VERSION)?;
version_path = Some(meta.path);
} else if meta.path == DEFAULT {
if meta.input.peek(Token![=]) {
if let Some(path) = parse_lit(ctx, &meta, DEFAULT)? {
default = Default::Path(path);
}
} else {
default = Default::Default;
default = Default::Default(meta.path);
}
} else {
let path = meta.path.to_token_stream().to_string();
@ -56,7 +58,7 @@ impl Field {
}
}
if version.is_some() && default.is_none() {
default = Default::Default;
default = Default::Default(version_path.unwrap());
}
Field { default, version }
@ -199,7 +201,7 @@ mod test {
assert_eq!(
field,
Field {
default: Default::Default,
default: Default::Default(parse_quote!(version)),
version: Some(parse_quote!(..34)),
}
);
@ -214,7 +216,7 @@ mod test {
assert_eq!(
field,
Field {
default: Default::Default,
default: Default::Default(parse_quote!(default)),
version: None,
}
);