Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions prdoc/pr_12227.prdoc
Original file line number Diff line number Diff line change
@@ -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<Task<Self>>` in pallet Config when using tasks"

doc:
- audience: Runtime Dev
description: |
Pallets using `#[pallet::tasks_experimental]` now automatically get
`frame_system::Config<RuntimeTask: From<Task<Self>>>` added as a supertrait
on their `Config` trait by the macro — mirroring the existing automatic
`RuntimeEvent: From<Event<Self>>` bound added for pallets with events.

Previously, pallet authors had to manually declare a `RuntimeTask` associated
type with the correct `From<Task<Self>>` 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
19 changes: 19 additions & 0 deletions substrate/frame/support/procedural/src/pallet/expand/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Task<Self>>` 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::<syn::TypeParamBound>(
quote! { #frame_system::Config<RuntimeTask: From<Task<#task_use_gen>>> },
)
.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 {
Expand Down