فهرست منبع

idl: Fix using constant identifiers as generic arguments (#3522)

acheron 8 ماه پیش
والد
کامیت
55d74c620d
3فایلهای تغییر یافته به همراه32 افزوده شده و 8 حذف شده
  1. 1 0
      CHANGELOG.md
  2. 26 7
      lang/syn/src/idl/defined.rs
  3. 5 1
      tests/idl/programs/new-idl/src/lib.rs

+ 1 - 0
CHANGELOG.md

@@ -113,6 +113,7 @@ The minor version will be incremented upon a breaking change and the patch versi
 - cli: Fix altering user-provided lib names ([#3467](https://github.com/coral-xyz/anchor/pull/3467)).
 - idl: Fix missing `program::seed` resolution ([#3474](https://github.com/coral-xyz/anchor/pull/3474)).
 - lang: Fix adding `derive`s and `repr`s to type alias definitions in `declare_program!` ([#3504](https://github.com/coral-xyz/anchor/pull/3504)).
+- idl: Fix using constant identifiers as generic arguments ([#3522](https://github.com/coral-xyz/anchor/pull/3522)).
 
 ### Breaking
 

+ 26 - 7
lang/syn/src/idl/defined.rs

@@ -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);
                     }
                 }
             }

+ 5 - 1
tests/idl/programs/new-idl/src/lib.rs

@@ -369,10 +369,14 @@ pub struct SomeStruct {
     pub field: u16,
 }
 
+/// Compilation check for the issue described in https://github.com/coral-xyz/anchor/issues/3520
+// TODO: Use this from client-side (instead of hardcoding) once `program.constants` is supported
+const GENERIC_CONST: usize = 8;
+
 #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
 pub struct GenericStruct<T, const N: usize> {
     arr: [T; N],
-    sub_field: SubGenericStruct<8, T, Vec<Option<T>>>,
+    sub_field: SubGenericStruct<GENERIC_CONST, T, Vec<Option<T>>>,
 }
 
 #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]