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 let mut query = None;
186
187 for runtime_type in runtime_types.iter() {
188 match runtime_type {
189 RuntimeType::RuntimeCall(_) => {
190 dispatch =
191 Some(expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate));
192 },
193 RuntimeType::RuntimeEvent(_) => {
194 outer_event = Some(expand::expand_outer_enum(
195 &name,
196 &pallets,
197 &scrate,
198 expand::OuterEnumType::Event,
199 )?);
200 },
201 RuntimeType::RuntimeError(_) => {
202 outer_error = Some(expand::expand_outer_enum(
203 &name,
204 &pallets,
205 &scrate,
206 expand::OuterEnumType::Error,
207 )?);
208 },
209 RuntimeType::RuntimeOrigin(_) => {
210 outer_origin =
211 Some(expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?);
212 },
213 RuntimeType::RuntimeFreezeReason(_) => {
214 freeze_reason = Some(expand::expand_outer_freeze_reason(&pallets, &scrate));
215 },
216 RuntimeType::RuntimeHoldReason(_) => {
217 hold_reason = Some(expand::expand_outer_hold_reason(&pallets, &scrate));
218 },
219 RuntimeType::RuntimeSlashReason(_) => {
220 slash_reason = Some(expand::expand_outer_slash_reason(&pallets, &scrate));
221 },
222 RuntimeType::RuntimeLockId(_) => {
223 lock_id = Some(expand::expand_outer_lock_id(&pallets, &scrate));
224 },
225 RuntimeType::RuntimeTask(_) => {
226 task = Some(expand::expand_outer_task(&name, &pallets, &scrate));
227 },
228 RuntimeType::RuntimeViewFunction(_) => {
229 query = Some(expand::expand_outer_query(&name, &pallets, &scrate));
230 },
231 }
232 }
233
234 let all_pallets = decl_all_pallets(&name, pallets.iter(), &features);
235 let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate);
236
237 let metadata = expand::expand_runtime_metadata(
238 &name,
239 &pallets,
240 &scrate,
241 &unchecked_extrinsic,
242 &system_pallet.path,
243 );
244 let outer_config: TokenStream2 = expand::expand_outer_config(&name, &pallets, &scrate);
245 let inherent =
246 expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate);
247 let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate);
248 let integrity_test = decl_integrity_test(&scrate);
249 let static_assertions = decl_static_assertions(&name, &pallets, &scrate);
250
251 let res = quote!(
252 #scrate_decl
253
254 const _: () = {
256 #[allow(unused)]
257 type __HiddenUseOfUncheckedExtrinsic = #unchecked_extrinsic;
258 };
259
260 #[derive(
261 Clone, Copy, PartialEq, Eq, #scrate::sp_runtime::RuntimeDebug,
262 #scrate::__private::scale_info::TypeInfo
263 )]
264 pub struct #name;
265 impl #scrate::sp_runtime::traits::GetRuntimeBlockType for #name {
266 type RuntimeBlock = #block;
267 }
268
269 #[doc(hidden)]
285 trait InternalConstructRuntime {
286 #[inline(always)]
287 fn runtime_metadata(&self) -> #scrate::__private::Vec<#scrate::__private::metadata_ir::RuntimeApiMetadataIR> {
288 Default::default()
289 }
290 }
291 #[doc(hidden)]
292 impl InternalConstructRuntime for &#name {}
293
294 #outer_event
295
296 #outer_error
297
298 #outer_origin
299
300 #all_pallets
301
302 #pallet_to_index
303
304 #dispatch
305
306 #task
307
308 #query
309
310 #metadata
311
312 #outer_config
313
314 #inherent
315
316 #validate_unsigned
317
318 #freeze_reason
319
320 #hold_reason
321
322 #lock_id
323
324 #slash_reason
325
326 #integrity_test
327
328 #static_assertions
329 );
330
331 Ok(res)
332}