Skip to content

Commit

Permalink
Merge maps when combining options
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Feb 11, 2024
1 parent 8ec5627 commit 548e860
Showing 1 changed file with 45 additions and 5 deletions.
50 changes: 45 additions & 5 deletions crates/ruff_macros/src/combine_options.rs
Expand Up @@ -48,13 +48,53 @@ fn handle_field(field: &Field) -> syn::Result<proc_macro2::TokenStream> {
..
}) => match segments.first() {
Some(PathSegment {
ident: type_ident, ..
}) if type_ident == "Option" => Ok(quote_spanned!(
ident.span() => #ident: self.#ident.or(other.#ident)
)),
ident: type_ident,
arguments,
}) if type_ident == "Option" => {
// Given `Option<FxHashMap<_>>`, combine the maps by merging. In TOML, a hash map is
// represented as a table, so merging the maps is the correct behavior.
if let syn::PathArguments::AngleBracketed(args) = arguments {
let inner_type_ident = args
.args
.first()
.and_then(|arg| match arg {
syn::GenericArgument::Type(ty) => match ty {
Type::Path(TypePath {
path: Path { segments, .. },
..
}) => segments.first().map(|seg| &seg.ident),
_ => None,
},
_ => None,
})
.ok_or_else(|| {
syn::Error::new(
ident.span(),
"Expected `Option<_>` with a single type argument.",
)
})?;
if inner_type_ident == "FxHashMap" {
return Ok(quote_spanned!(
ident.span() => #ident: match (self.#ident, other.#ident) {
(Some(mut m1), Some(m2)) => {
m1.extend(m2);
Some(m1)
},
(None, Some(m)) | (Some(m), None) => Some(m),
(None, None) => None,
}
));
}
}

Ok(quote_spanned!(
ident.span() => #ident: self.#ident.or(other.#ident)
))
}

_ => Err(syn::Error::new(
ident.span(),
"Expected `Option<_>` or `Vec<_>` as type.",
"Expected `Option<_>` as type.",
)),
},
_ => Err(syn::Error::new(ident.span(), "Expected type.")),
Expand Down

0 comments on commit 548e860

Please sign in to comment.