diff --git a/prdoc/pr_12227.prdoc b/prdoc/pr_12227.prdoc new file mode 100644 index 0000000000000..396be56bcd021 --- /dev/null +++ b/prdoc/pr_12227.prdoc @@ -0,0 +1,32 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "[FRAME] Auto-bound `RuntimeTask: From>` in pallet Config when using tasks" + +doc: + - audience: Runtime Dev + description: | + Pallets using `#[pallet::tasks_experimental]` now automatically get + `frame_system::Config>>` added as a supertrait + on their `Config` trait by the macro — mirroring the existing automatic + `RuntimeEvent: From>` bound added for pallets with events. + + Previously, pallet authors had to manually declare a `RuntimeTask` associated + type with the correct `From>` bound, or omit it entirely with no + compile-time enforcement. Now the compiler enforces that any runtime including + a task-bearing pallet must have a `RuntimeTask` type that can represent that + pallet's tasks. + + This change is backward compatible: existing pallets that already declare + `RuntimeTask` manually continue to compile unchanged. Runtimes built with + `construct_runtime!` already satisfy the new bound since the macro generates + the required `From` impl for each pallet with tasks. + + The system pallet itself is exempt via the existing + `#[pallet::config(frame_system_config)]` attribute. + +crates: + - name: frame-support-procedural + bump: minor + - name: frame-support + bump: minor diff --git a/substrate/frame/support/procedural/src/pallet/expand/config.rs b/substrate/frame/support/procedural/src/pallet/expand/config.rs index 751a85d3e0327..ed84df10c477c 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/config.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/config.rs @@ -72,6 +72,25 @@ Consequently, a runtime that wants to include this pallet must implement this tr } } + // insert `frame_system::Config` supertrait with `RuntimeTask: From>` if tasks are + // defined for this pallet. + if def.tasks.is_some() && !def.is_frame_system { + let frame_system = &def.frame_system; + + let task_use_gen = if def.config.has_instance { + quote! { Self, I } + } else { + quote! { Self } + }; + + let supertrait_with_task_bound = syn::parse2::( + quote! { #frame_system::Config>> }, + ) + .expect("Parsing super trait doesn't fail; qed"); + + config_item.supertraits.push(supertrait_with_task_bound.into()); + } + // we only emit `DefaultConfig` if there are trait items, so an empty `DefaultConfig` is // impossible consequently. match &config.default_sub_trait {