frame_support_procedural/runtime/expand/
mod.rs1use super::parse::runtime_types::RuntimeType;
19use crate::{
20 construct_runtime::{
21 check_pallet_number, decl_all_pallets, decl_integrity_test, decl_pallet_runtime_setup,
22 decl_static_assertions, expand,
23 },
24 runtime::{
25 parse::{
26 AllPalletsDeclaration, ExplicitAllPalletsDeclaration, ImplicitAllPalletsDeclaration,
27 },
28 Def,
29 },
30};
31use cfg_expr::Predicate;
32use frame_support_procedural_tools::{
33 generate_access_from_frame_or_crate, generate_crate_access, generate_hidden_includes,
34};
35use proc_macro2::TokenStream as TokenStream2;
36use quote::quote;
37use std::collections::HashSet;
38use syn::{Ident, Result};
39
40const SYSTEM_PALLET_NAME: &str = "System";
42
43pub fn expand(def: Def, legacy_ordering: bool) -> TokenStream2 {
44 let input = def.input;
45
46 let (check_pallet_number_res, res) = match def.pallets {
47 AllPalletsDeclaration::Implicit(ref decl) => (
48 check_pallet_number(input.clone(), decl.pallet_count),
49 construct_runtime_implicit_to_explicit(input.into(), decl.clone(), legacy_ordering),
50 ),
51 AllPalletsDeclaration::Explicit(ref decl) => (
52 check_pallet_number(input, decl.pallets.len()),
53 construct_runtime_final_expansion(
54 def.runtime_struct.ident.clone(),
55 decl.clone(),
56 def.runtime_types.clone(),
57 legacy_ordering,
58 ),
59 ),
60 };
61
62 let res = res.unwrap_or_else(|e| e.to_compile_error());
63
64 let res = if let Err(error) = check_pallet_number_res {
68 let error = error.to_compile_error();
69
70 quote! {
71 #error
72
73 #res
74 }
75 } else {
76 res
77 };
78
79 let res = expander::Expander::new("construct_runtime")
80 .dry(std::env::var("EXPAND_MACROS").is_err())
81 .verbose(true)
82 .write_to_out_dir(res)
83 .expect("Does not fail because of IO in OUT_DIR; qed");
84
85 res.into()
86}
87
88fn construct_runtime_implicit_to_explicit(
89 input: TokenStream2,
90 definition: ImplicitAllPalletsDeclaration,
91 legacy_ordering: bool,
92) -> Result<TokenStream2> {
93 let frame_support = generate_access_from_frame_or_crate("frame-support")?;
94 let attr = if legacy_ordering { quote!((legacy_ordering)) } else { quote!() };
95 let mut expansion = quote::quote!(
96 #[#frame_support::runtime #attr]
97 #input
98 );
99 for pallet in definition.pallet_decls.iter() {
100 let pallet_path = &pallet.path;
101 let pallet_name = &pallet.name;
102 let runtime_param = &pallet.runtime_param;
103 let pallet_segment_and_instance = match (&pallet.pallet_segment, &pallet.instance) {
104 (Some(segment), Some(instance)) => quote::quote!(::#segment<#runtime_param, #instance>),
105 (Some(segment), None) => quote::quote!(::#segment<#runtime_param>),
106 (None, Some(instance)) => quote::quote!(<#instance>),
107 (None, None) => quote::quote!(),
108 };
109 expansion = quote::quote!(
110 #frame_support::__private::tt_call! {
111 macro = [{ #pallet_path::tt_default_parts_v2 }]
112 your_tt_return = [{ #frame_support::__private::tt_return }]
113 ~~> #frame_support::match_and_insert! {
114 target = [{ #expansion }]
115 pattern = [{ #pallet_name = #pallet_path #pallet_segment_and_instance }]
116 }
117 }
118 );
119 }
120
121 Ok(expansion)
122}
123
124fn construct_runtime_final_expansion(
125 name: Ident,
126 definition: ExplicitAllPalletsDeclaration,
127 runtime_types: Vec<RuntimeType>,
128 legacy_ordering: bool,
129) -> Result<TokenStream2> {
130 let ExplicitAllPalletsDeclaration { mut pallets, name: pallets_name } = definition;
131
132 if !legacy_ordering {
133 pallets.sort_by_key(|p| p.index);
135 }
136
137 let system_pallet =
138 pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| {
139 syn::Error::new(
140 pallets_name.span(),
141 "`System` pallet declaration is missing. \
142 Please add this line: `pub type System = frame_system;`",
143 )
144 })?;
145 if !system_pallet.cfg_pattern.is_empty() {
146 return Err(syn::Error::new(
147 system_pallet.name.span(),
148 "`System` pallet declaration is feature gated, please remove any `#[cfg]` attributes",
149 ))
150 }
151
152 let features = pallets
153 .iter()
154 .filter_map(|decl| {
155 (!decl.cfg_pattern.is_empty()).then(|| {
156 decl.cfg_pattern.iter().flat_map(|attr| {
157 attr.predicates().filter_map(|pred| match pred {
158 Predicate::Feature(feat) => Some(feat),
159 Predicate::Test => Some("test"),
160 _ => None,
161 })
162 })
163 })
164 })
165 .flatten()
166 .collect::<HashSet<_>>();
167
168 let hidden_crate_name = "construct_runtime";
169 let scrate = generate_crate_access(hidden_crate_name, "frame-support");
170 let scrate_decl = generate_hidden_includes(hidden_crate_name, "frame-support");
171
172 let frame_system = generate_access_from_frame_or_crate("frame-system")?;
173 let block = quote!(<#name as #frame_system::Config>::Block);
174 let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic);
175
176 let mut dispatch = None;
177 let mut outer_event = None;
178 let mut outer_error = None;
179 let mut outer_origin = None;
180 let mut freeze_reason = None;
181 let mut hold_reason = None;
182 let mut slash_reason = None;
183 let mut lock_id = None;
184 let mut task = None;
185
186 for runtime_type in runtime_types.iter() {
187 match runtime_type {
188 RuntimeType::RuntimeCall(_) => {
189 dispatch =
190 Some(expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate));
191 },
192 RuntimeType::RuntimeEvent(_) => {
193 outer_event = Some(expand::expand_outer_enum(
194 &name,
195 &pallets,
196 &scrate,
197 expand::OuterEnumType::Event,
198 )?);
199 },
200 RuntimeType::RuntimeError(_) => {
201 outer_error = Some(expand::expand_outer_enum(
202 &name,
203 &pallets,
204 &scrate,
205 expand::OuterEnumType::Error,
206 )?);
207 },
208 RuntimeType::RuntimeOrigin(_) => {
209 outer_origin =
210 Some(expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?);
211 },
212 RuntimeType::RuntimeFreezeReason(_) => {
213 freeze_reason = Some(expand::expand_outer_freeze_reason(&pallets, &scrate));
214 },
215 RuntimeType::RuntimeHoldReason(_) => {
216 hold_reason = Some(expand::expand_outer_hold_reason(&pallets, &scrate));
217 },
218 RuntimeType::RuntimeSlashReason(_) => {
219 slash_reason = Some(expand::expand_outer_slash_reason(&pallets, &scrate));
220 },
221 RuntimeType::RuntimeLockId(_) => {
222 lock_id = Some(expand::expand_outer_lock_id(&pallets, &scrate));
223 },
224 RuntimeType::RuntimeTask(_) => {
225 task = Some(expand::expand_outer_task(&name, &pallets, &scrate));
226 },
227 }
228 }
229
230 let all_pallets = decl_all_pallets(&name, pallets.iter(), &features);
231 let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate);
232
233 let metadata = expand::expand_runtime_metadata(
234 &name,
235 &pallets,
236 &scrate,
237 &unchecked_extrinsic,
238 &system_pallet.path,
239 );
240 let outer_config = expand::expand_outer_config(&name, &pallets, &scrate);
241 let inherent =
242 expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate);
243 let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate);
244 let integrity_test = decl_integrity_test(&scrate);
245 let static_assertions = decl_static_assertions(&name, &pallets, &scrate);
246
247 let res = quote!(
248 #scrate_decl
249
250 const _: () = {
252 #[allow(unused)]
253 type __HiddenUseOfUncheckedExtrinsic = #unchecked_extrinsic;
254 };
255
256 #[derive(
257 Clone, Copy, PartialEq, Eq, #scrate::sp_runtime::RuntimeDebug,
258 #scrate::__private::scale_info::TypeInfo
259 )]
260 pub struct #name;
261 impl #scrate::sp_runtime::traits::GetRuntimeBlockType for #name {
262 type RuntimeBlock = #block;
263 }
264
265 #[doc(hidden)]
281 trait InternalConstructRuntime {
282 #[inline(always)]
283 fn runtime_metadata(&self) -> #scrate::__private::Vec<#scrate::__private::metadata_ir::RuntimeApiMetadataIR> {
284 Default::default()
285 }
286 }
287 #[doc(hidden)]
288 impl InternalConstructRuntime for &#name {}
289
290 #outer_event
291
292 #outer_error
293
294 #outer_origin
295
296 #all_pallets
297
298 #pallet_to_index
299
300 #dispatch
301
302 #task
303
304 #metadata
305
306 #outer_config
307
308 #inherent
309
310 #validate_unsigned
311
312 #freeze_reason
313
314 #hold_reason
315
316 #lock_id
317
318 #slash_reason
319
320 #integrity_test
321
322 #static_assertions
323 );
324
325 Ok(res)
326}