|
@@ -581,17 +581,36 @@ pub fn gen_idl_type(
|
|
|
if let Some(segment) = path.path.segments.last() {
|
|
|
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
|
|
|
for arg in &args.args {
|
|
|
- match arg {
|
|
|
+ let generic = match arg {
|
|
|
+ syn::GenericArgument::Const(c) => {
|
|
|
+ quote! { #idl::IdlGenericArg::Const { value: #c.to_string() } }
|
|
|
+ }
|
|
|
+ // `MY_CONST` in `Foo<MY_CONST>` is parsed as `GenericArgument::Type`
|
|
|
+ // instead of `GenericArgument::Const` because they're indistinguishable
|
|
|
+ // syntactically, as mentioned in
|
|
|
+ // https://github.com/dtolnay/syn/blob/bfa790b8e445dc67b7ab94d75adb1a92d6296c9a/src/path.rs#L113-L115
|
|
|
+ //
|
|
|
+ // As a workaround, we're manually checking to see if it *looks* like a
|
|
|
+ // constant identifier to fix the issue mentioned in
|
|
|
+ // https://github.com/coral-xyz/anchor/issues/3520
|
|
|
+ syn::GenericArgument::Type(syn::Type::Path(p))
|
|
|
+ if p.path
|
|
|
+ .segments
|
|
|
+ .last()
|
|
|
+ .map(|seg| seg.ident.to_string())
|
|
|
+ .map(|ident| ident.len() > 1 && ident == ident.to_uppercase())
|
|
|
+ .unwrap_or_default() =>
|
|
|
+ {
|
|
|
+ quote! { #idl::IdlGenericArg::Const { value: #p.to_string() } }
|
|
|
+ }
|
|
|
syn::GenericArgument::Type(ty) => {
|
|
|
let (ty, def) = gen_idl_type(ty, generic_params)?;
|
|
|
- generics.push(quote! { #idl::IdlGenericArg::Type { ty: #ty } });
|
|
|
defined.extend(def);
|
|
|
+ quote! { #idl::IdlGenericArg::Type { ty: #ty } }
|
|
|
}
|
|
|
- syn::GenericArgument::Const(c) => generics.push(
|
|
|
- quote! { #idl::IdlGenericArg::Const { value: #c.to_string() } },
|
|
|
- ),
|
|
|
- _ => (),
|
|
|
- }
|
|
|
+ _ => return Err(anyhow!("Unsupported generic argument: {arg:#?}")),
|
|
|
+ };
|
|
|
+ generics.push(generic);
|
|
|
}
|
|
|
}
|
|
|
}
|