From 19f1edae78f696cc89e7e488a657af5085c51876 Mon Sep 17 00:00:00 2001 From: Saif Ali Date: Fri, 21 Nov 2025 13:22:35 +0530 Subject: [PATCH 1/2] This commit: 1. Updates `get_pda` to correctly locate seeds defined within `init` constraints. 2. Adds an explicit check for parsing errors. Instead of silently swallowing errors with `.ok()`, it now prints a warning to stderr explaining that IDL generation was skipped for the specific account due to complex expressions. --- lang/syn/src/idl/accounts.rs | 41 +++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/lang/syn/src/idl/accounts.rs b/lang/syn/src/idl/accounts.rs index b481281f46..d2ba43058c 100644 --- a/lang/syn/src/idl/accounts.rs +++ b/lang/syn/src/idl/accounts.rs @@ -192,10 +192,45 @@ fn get_pda(acc: &Field, accounts: &AccountsStruct) -> TokenStream { let parse_default = |expr: &syn::Expr| parse_seed(expr, accounts); // Seeds - let seed_constraints = acc.constraints.seeds.as_ref(); + // check for seeds in two places: + // 1. The standard `seeds = [...]` constraint. + // 2. The `init` constraint, which may contain `seeds` (e.g. `init, seeds = [...]`). + // This ensures we find the seeds regardless of how the user defined them. + let seed_constraints = acc.constraints.seeds.as_ref().or_else(|| { + acc.constraints + .init + .as_ref() + .and_then(|init| init.seeds.as_ref()) + }); + + // Parse Seeds let pda = seed_constraints - .map(|seed| seed.seeds.iter().map(parse_default)) - .and_then(|seeds| seeds.collect::>>().ok()) + .and_then(|seed| { + // Try to parse every seed in the list. + // Collect into a Vec so we can inspect individual failures. + let results: Vec> = + seed.seeds.iter().map(parse_default).collect(); + + // CHECK FOR ERRORS: + // If `any` seed failed to parse (returns Err), it means the user used syntax that IDL doesn't support + if results.iter().any(|r| r.is_err()) { + // Instead of failing silently, we print a warning to stderr. + // usage of `eprintln!` ensures the user sees it in their terminal during build. + let name = acc.ident.to_string(); + eprintln!( + "WARNING: Anchor IDL generation skipped for PDA seeds in account '{}'. \ + Reason: Seeds contain unsupported complex expressions (e.g., function calls). \ + Workaround: Derive this PDA manually in your client.", + name + ); + + // Return None. This is safe; it simply omits the `pda` field from the JSON, + None + } else { + // If all seeds parsed correctly, unwrap them and return the vector. + Some(results.into_iter().map(|r| r.unwrap()).collect::>()) + } + }) .and_then(|seeds| { let program = match seed_constraints { Some(ConstraintSeedsGroup { From 00da8106a0ccee0e34e1866463d603cb3d089808 Mon Sep 17 00:00:00 2001 From: Nanasi Date: Thu, 11 Jun 2026 14:46:41 -0400 Subject: [PATCH 2/2] Warn on unsupported seeds::program IDL seeds --- lang/syn/src/idl/accounts.rs | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/lang/syn/src/idl/accounts.rs b/lang/syn/src/idl/accounts.rs index d2ba43058c..58635da132 100644 --- a/lang/syn/src/idl/accounts.rs +++ b/lang/syn/src/idl/accounts.rs @@ -214,14 +214,9 @@ fn get_pda(acc: &Field, accounts: &AccountsStruct) -> TokenStream { // CHECK FOR ERRORS: // If `any` seed failed to parse (returns Err), it means the user used syntax that IDL doesn't support if results.iter().any(|r| r.is_err()) { - // Instead of failing silently, we print a warning to stderr. - // usage of `eprintln!` ensures the user sees it in their terminal during build. - let name = acc.ident.to_string(); - eprintln!( - "WARNING: Anchor IDL generation skipped for PDA seeds in account '{}'. \ - Reason: Seeds contain unsupported complex expressions (e.g., function calls). \ - Workaround: Derive this PDA manually in your client.", - name + warn_skipped_pda_seed( + acc, + "Seeds contain unsupported complex expressions (e.g., function calls)", ); // Return None. This is safe; it simply omits the `pda` field from the JSON, @@ -236,9 +231,16 @@ fn get_pda(acc: &Field, accounts: &AccountsStruct) -> TokenStream { Some(ConstraintSeedsGroup { program_seed: Some(program), .. - }) => parse_default(program) - .map(|program| quote! { Some(#program) }) - .ok()?, + }) => match parse_default(program) { + Ok(program) => quote! { Some(#program) }, + Err(_) => { + warn_skipped_pda_seed( + acc, + "seeds::program contains unsupported complex expressions (e.g., function calls)", + ); + return None; + } + }, _ => quote! { None }, }; @@ -311,6 +313,16 @@ fn get_pda(acc: &Field, accounts: &AccountsStruct) -> TokenStream { quote! { None } } +fn warn_skipped_pda_seed(acc: &Field, reason: &str) { + let name = acc.ident.to_string(); + eprintln!( + "WARNING: Anchor IDL generation skipped for PDA seeds in account '{}'. \ + Reason: {}. \ + Workaround: Derive this PDA manually in your client.", + name, reason + ); +} + /// Parse a seeds constraint, extracting the `IdlSeed` types. /// /// Note: This implementation makes assumptions about the types that can be used (e.g., no