Skip to content

fix: remove trait bounds from where clause in IntoWasmAbi expansion - #72

Closed
dsgallups wants to merge 3 commits into
madonoharu:mainfrom
Adversarial-Risk-Management:associated-item-constraints
Closed

fix: remove trait bounds from where clause in IntoWasmAbi expansion#72
dsgallups wants to merge 3 commits into
madonoharu:mainfrom
Adversarial-Risk-Management:associated-item-constraints

Conversation

@dsgallups

Copy link
Copy Markdown
Contributor

This PR fixes an issue with trait implementation where you have

use tsify::Tsify;

pub trait Constraint {}

#[derive(Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct GenericStruct<T: Constraint> {
    x: T,
}
error[E0229]: associated item constraints are not allowed here
  |
  | pub struct GenericStruct<T: Constraint> {
  |                          ^^^^^^^^^^^^^ associated item constraint not allowed here

This is because the implementation of traits would have an invalidate generic constraint in the where clause:

    #[automatically_derived]
    impl<T: Constraint> IntoWasmAbi for &GenericStruct<T>
    where
        GenericStruct<T: Constraint>: _serde::Serialize,

This has been fixed:

    #[automatically_derived]
    impl<T: Constraint> IntoWasmAbi for &GenericStruct<T>
    where
        GenericStruct<T>: _serde::Serialize,

Comment thread tsify-macros/src/container.rs Outdated
@madonoharu

Copy link
Copy Markdown
Owner

Sorry this sat for so long — thanks for tracking the bug down. The diagnosis is exactly right: wasm_bindgen.rs interpolated a raw syn::Generics into a type position, and Generics::to_tokens emits the declaration form (bounds included), which is what trips E0229.

Two things came up while getting it ready to land:

1. split_for_impl().1 handles all three parameter kinds. The hand-built stripped Generics clears bounds on type params only, so <'a: 'b, 'b> and <const N: usize> still reach the type position. I reproduced that against your branch — the derive panics with expected ',' on both:

#[derive(Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)]
pub struct GenericLifetime<'a: 'b, 'b> { x: &'a str, y: &'b str }

#[derive(Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)]
pub struct GenericConst<const N: usize> { x: u32 }

TypeGenerics is syn's type-position rendering, so materialising the predicate first fixes all three at once and drops the hand-rolled block:

let predicate: syn::WherePredicate = {
    let (_, ty_generics, _) = generics.split_for_impl();
    parse_quote!(#ident #ty_generics: #serde_path::Serialize)
};
generics.make_where_clause().predicates.push(predicate);

2. The expected output needs regenerating. main has since landed the expandtest fix (#87), so the snapshots are now fully expanded — generic_constrained_struct.expanded.rs grows from 498 to ~2160 lines.

Since this branch doesn't have "Allow edits from maintainers" enabled, I can't push these here, so I've opened #89 with your commits rebased onto main and the two changes above on top. Your commits keep their authorship. Happy to close that one instead if you'd rather finish this PR — just say the word.

@madonoharu

Copy link
Copy Markdown
Owner

Landed in #89 (269b3dd) — your commits carried through with co-author credit. Thanks again for finding this, and sorry it took so long to get in.

Closing this one as superseded.

@madonoharu madonoharu closed this Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants