Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion crates/sol-macro-expander/src/expand/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,12 @@ struct ExpandData {
min_data_len: usize,
trait_: Ident,
selectors: Vec<ExprArray<u8>>,
/// Whether the builtin `#[sol(all_derives)]` traits can be derived on the
/// generated enum. Computed from the underlying items' parameter types,
/// because the variant type names may be synthetic (overloaded items get
/// `_N` suffixes, call variants use `*Call` structs) and thus not
/// resolvable as items.
can_derive_builtin: bool,
}

impl ExpandData {
Expand Down Expand Up @@ -645,6 +651,9 @@ impl ToExpand<'_> {
.unwrap(),
trait_: format_ident!("SolCall"),
selectors: functions.iter().map(|f| cx.function_selector(f)).collect(),
can_derive_builtin: functions
.iter()
.all(|f| f.parameters.types().all(|ty| cx.can_derive_builtin_traits(ty))),
}
}

Expand All @@ -659,6 +668,9 @@ impl ToExpand<'_> {
.unwrap(),
trait_: format_ident!("SolError"),
selectors: errors.iter().map(|e| cx.error_selector(e)).collect(),
can_derive_builtin: errors.iter().all(|&error| {
error.parameters.types().all(|ty| cx.can_derive_builtin_traits(ty))
}),
},

Self::Events(events) => {
Expand All @@ -676,6 +688,9 @@ impl ToExpand<'_> {
.unwrap(),
trait_: format_ident!("SolEvent"),
selectors: events.iter().map(|e| cx.event_selector(e)).collect(),
can_derive_builtin: events.iter().all(|&event| {
event.parameters.iter().all(|p| cx.can_derive_builtin_traits(&p.ty))
}),
}
}
}
Expand Down Expand Up @@ -918,7 +933,7 @@ impl CallLikeExpander<'_> {
assert!(selectors.iter().all(|s| s.array.len() == selector_len));
let selector_type = quote!([u8; #selector_len]);

self.cx.type_derives(&mut attrs, types.iter().cloned().map(ast::Type::custom), false);
self.cx.enum_derives(&mut attrs, data.can_derive_builtin);
let trait_ = &data.trait_;

let mut tokens = quote! {
Expand Down
20 changes: 20 additions & 0 deletions crates/sol-macro-expander/src/expand/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,26 @@ impl<'ast> ExpCtxt<'ast> {
attrs.push(parse_quote! { #[derive(#(#derives), *)] });
}

/// Like [`type_derives`](Self::type_derives), but for the generated `*Calls`
/// / `*Errors` / `*Events` enums.
///
/// The enum variant types may be synthetic names that don't resolve as
/// items (overloaded items get `_N` suffixes; call variants use `*Call`
/// structs), so whether the builtin traits can be derived is precomputed
/// from the underlying items' parameter types. Enums never derive
/// `Default`.
fn enum_derives(&self, attrs: &mut Vec<Attribute>, can_derive_builtin: bool) {
if let Some(extra) = &self.attrs.extra_derives {
if !extra.is_empty() {
attrs.push(parse_quote! { #[derive(#(#extra),*)] });
}
}

if self.attrs.all_derives == Some(true) && can_derive_builtin {
attrs.push(parse_quote! { #[derive(Debug, PartialEq, Eq, Hash)] });
}
}
Comment thread
DaniPopes marked this conversation as resolved.

/// Returns an error if any of the types in the parameters are unresolved.
///
/// Provides a better error message than an `unwrap` or `expect` when we
Expand Down
32 changes: 32 additions & 0 deletions crates/sol-types/tests/derives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,35 @@ fn test_extra_derives() {
// Should not increase size since they're equal
assert_eq!(calls_set.len(), 1);
}

// Overloaded events (same name, different params) get suffixed variant names
// (e.g. `Swap_0`, `Swap_1`). The generated `*Events` enum must still receive
// the `#[sol(all_derives)]` traits. See alloy-rs/alloy#3856.
#[test]
#[allow(non_snake_case)]
fn test_all_derives_overloaded_events() {
sol! {
#[sol(all_derives)]
contract OverloadedEvents {
event Swap(address indexed sender, uint256 amount0);
event Swap(address indexed sender, address indexed to, int256 amount0, int256 amount1);
}
}

use OverloadedEvents::*;

let a =
OverloadedEventsEvents::Swap_0(Swap_0 { sender: Address::ZERO, amount0: U256::from(1) });
let b =
OverloadedEventsEvents::Swap_0(Swap_0 { sender: Address::ZERO, amount0: U256::from(1) });

// Debug + PartialEq
assert_eq!(a, b);
let _ = format!("{a:?}");

// Hash + Eq
let mut set = HashSet::new();
set.insert(a);
set.insert(b);
assert_eq!(set.len(), 1);
}