referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/pallet/parse/
mod.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Parse for pallet macro.
19//!
20//! Parse the module into `Def` struct through `Def::try_from` function.
21
22pub mod call;
23pub mod composite;
24pub mod config;
25pub mod error;
26pub mod event;
27pub mod extra_constants;
28pub mod genesis_build;
29pub mod genesis_config;
30pub mod helper;
31pub mod hooks;
32pub mod inherent;
33pub mod origin;
34pub mod pallet_struct;
35pub mod storage;
36pub mod tasks;
37pub mod type_value;
38pub mod validate_unsigned;
39pub mod view_functions;
40
41#[cfg(test)]
42pub mod tests;
43
44use composite::{keyword::CompositeKeyword, CompositeDef};
45use frame_support_procedural_tools::generate_access_from_frame_or_crate;
46use quote::ToTokens;
47use syn::spanned::Spanned;
48
49/// Parsed definition of a pallet.
50pub struct Def {
51	/// The module items.
52	/// (their order must not be modified because they are registered in individual definitions).
53	pub item: syn::ItemMod,
54	pub config: config::ConfigDef,
55	pub pallet_struct: pallet_struct::PalletStructDef,
56	pub hooks: Option<hooks::HooksDef>,
57	pub call: Option<call::CallDef>,
58	pub tasks: Option<tasks::TasksDef>,
59	pub task_enum: Option<tasks::TaskEnumDef>,
60	pub storages: Vec<storage::StorageDef>,
61	pub error: Option<error::ErrorDef>,
62	pub event: Option<event::EventDef>,
63	pub origin: Option<origin::OriginDef>,
64	pub inherent: Option<inherent::InherentDef>,
65	pub genesis_config: Option<genesis_config::GenesisConfigDef>,
66	pub genesis_build: Option<genesis_build::GenesisBuildDef>,
67	pub validate_unsigned: Option<validate_unsigned::ValidateUnsignedDef>,
68	pub extra_constants: Option<extra_constants::ExtraConstantsDef>,
69	pub composites: Vec<composite::CompositeDef>,
70	pub type_values: Vec<type_value::TypeValueDef>,
71	pub frame_system: syn::Path,
72	pub frame_support: syn::Path,
73	pub dev_mode: bool,
74	pub view_functions: Option<view_functions::ViewFunctionsImplDef>,
75	pub is_frame_system: bool,
76}
77
78impl Def {
79	pub fn try_from(mut item: syn::ItemMod, dev_mode: bool) -> syn::Result<Self> {
80		let frame_system = generate_access_from_frame_or_crate("frame-system")?;
81		let frame_support = generate_access_from_frame_or_crate("frame-support")?;
82		let item_span = item.span();
83		let items = &mut item
84			.content
85			.as_mut()
86			.ok_or_else(|| {
87				let msg = "Invalid pallet definition, expected mod to be inlined.";
88				syn::Error::new(item_span, msg)
89			})?
90			.1;
91
92		let mut config = None;
93		let mut pallet_struct = None;
94		let mut hooks = None;
95		let mut call = None;
96		let mut tasks = None;
97		let mut task_enum = None;
98		let mut error = None;
99		let mut event = None;
100		let mut origin = None;
101		let mut inherent = None;
102		let mut genesis_config = None;
103		let mut genesis_build = None;
104		let mut validate_unsigned = None;
105		let mut extra_constants = None;
106		let mut storages = vec![];
107		let mut type_values = vec![];
108		let mut composites: Vec<CompositeDef> = vec![];
109		let mut view_functions = None;
110		let mut is_frame_system = false;
111
112		for (index, item) in items.iter_mut().enumerate() {
113			let pallet_attr: Option<PalletAttr> = helper::take_first_item_pallet_attr(item)?;
114
115			match pallet_attr {
116				Some(PalletAttr::Config{ with_default, frame_system_config: is_frame_system_val, without_automatic_metadata, ..}) if config.is_none() => {
117					is_frame_system = is_frame_system_val;
118					config = Some(config::ConfigDef::try_from(
119						&frame_system,
120						index,
121						item,
122						with_default,
123						without_automatic_metadata,
124						is_frame_system,
125					)?);
126				},
127				Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => {
128					let p = pallet_struct::PalletStructDef::try_from(span, index, item)?;
129					pallet_struct = Some(p);
130				},
131				Some(PalletAttr::Hooks(span)) if hooks.is_none() => {
132					let m = hooks::HooksDef::try_from(span, item)?;
133					hooks = Some(m);
134				},
135				Some(PalletAttr::RuntimeCall(cw, span)) if call.is_none() =>
136					call = Some(call::CallDef::try_from(span, index, item, dev_mode, cw)?),
137				Some(PalletAttr::Tasks(span)) if tasks.is_none() => {
138					let item_tokens = item.to_token_stream();
139					// `TasksDef::parse` needs to know if attr was provided so we artificially
140					// re-insert it here
141					tasks = Some(syn::parse2::<tasks::TasksDef>(quote::quote_spanned! { span =>
142						#[pallet::tasks_experimental]
143						#item_tokens
144					})?);
145
146					// replace item with a no-op because it will be handled by the expansion of tasks
147					*item = syn::Item::Verbatim(quote::quote!());
148				}
149				Some(PalletAttr::TaskCondition(span)) => return Err(syn::Error::new(
150					span,
151					"`#[pallet::task_condition]` can only be used on items within an `impl` statement."
152				)),
153				Some(PalletAttr::TaskIndex(span)) => return Err(syn::Error::new(
154					span,
155					"`#[pallet::task_index]` can only be used on items within an `impl` statement."
156				)),
157				Some(PalletAttr::TaskList(span)) => return Err(syn::Error::new(
158					span,
159					"`#[pallet::task_list]` can only be used on items within an `impl` statement."
160				)),
161				Some(PalletAttr::RuntimeTask(_)) if task_enum.is_none() =>
162					task_enum = Some(syn::parse2::<tasks::TaskEnumDef>(item.to_token_stream())?),
163				Some(PalletAttr::Error(span)) if error.is_none() =>
164					error = Some(error::ErrorDef::try_from(span, index, item)?),
165				Some(PalletAttr::RuntimeEvent(span)) if event.is_none() =>
166					event = Some(event::EventDef::try_from(span, index, item)?),
167				Some(PalletAttr::GenesisConfig(_)) if genesis_config.is_none() => {
168					let g = genesis_config::GenesisConfigDef::try_from(index, item)?;
169					genesis_config = Some(g);
170				},
171				Some(PalletAttr::GenesisBuild(span)) if genesis_build.is_none() => {
172					let g = genesis_build::GenesisBuildDef::try_from(span, item)?;
173					genesis_build = Some(g);
174				},
175				Some(PalletAttr::RuntimeOrigin(_)) if origin.is_none() =>
176					origin = Some(origin::OriginDef::try_from(item)?),
177				Some(PalletAttr::Inherent(_)) if inherent.is_none() =>
178					inherent = Some(inherent::InherentDef::try_from(item)?),
179				Some(PalletAttr::Storage(span)) =>
180					storages.push(storage::StorageDef::try_from(span, index, item, dev_mode)?),
181				Some(PalletAttr::ValidateUnsigned(_)) if validate_unsigned.is_none() => {
182					let v = validate_unsigned::ValidateUnsignedDef::try_from(item)?;
183					validate_unsigned = Some(v);
184				},
185				Some(PalletAttr::TypeValue(span)) =>
186					type_values.push(type_value::TypeValueDef::try_from(span, index, item)?),
187				Some(PalletAttr::ExtraConstants(_)) =>
188					extra_constants =
189						Some(extra_constants::ExtraConstantsDef::try_from(item)?),
190				Some(PalletAttr::Composite(span)) => {
191					let composite =
192						composite::CompositeDef::try_from(span, &frame_support, item)?;
193					if composites.iter().any(|def| {
194						match (&def.composite_keyword, &composite.composite_keyword) {
195							(
196								CompositeKeyword::FreezeReason(_),
197								CompositeKeyword::FreezeReason(_),
198							) |
199							(CompositeKeyword::HoldReason(_), CompositeKeyword::HoldReason(_)) |
200							(CompositeKeyword::LockId(_), CompositeKeyword::LockId(_)) |
201							(
202								CompositeKeyword::SlashReason(_),
203								CompositeKeyword::SlashReason(_),
204							) => true,
205							_ => false,
206						}
207					}) {
208						let msg = format!(
209							"Invalid duplicated `{}` definition",
210							composite.composite_keyword
211						);
212						return Err(syn::Error::new(composite.composite_keyword.span(), &msg))
213					}
214					composites.push(composite);
215				},
216				Some(PalletAttr::ViewFunctions(span)) => {
217					view_functions = Some(view_functions::ViewFunctionsImplDef::try_from(span, item)?);
218				}
219				Some(attr) => {
220					let msg = "Invalid duplicated attribute";
221					return Err(syn::Error::new(attr.span(), msg))
222				},
223				None => (),
224			}
225		}
226
227		if genesis_config.is_some() != genesis_build.is_some() {
228			let msg = format!(
229				"`#[pallet::genesis_config]` and `#[pallet::genesis_build]` attributes must be \
230				either both used or both not used, instead genesis_config is {} and genesis_build \
231				is {}",
232				genesis_config.as_ref().map_or("unused", |_| "used"),
233				genesis_build.as_ref().map_or("unused", |_| "used"),
234			);
235			return Err(syn::Error::new(item_span, msg));
236		}
237
238		Self::resolve_tasks(&item_span, &mut tasks, &mut task_enum, items)?;
239
240		let def = Def {
241			item,
242			config: config
243				.ok_or_else(|| syn::Error::new(item_span, "Missing `#[pallet::config]`"))?,
244			pallet_struct: pallet_struct
245				.ok_or_else(|| syn::Error::new(item_span, "Missing `#[pallet::pallet]`"))?,
246			hooks,
247			call,
248			tasks,
249			task_enum,
250			extra_constants,
251			genesis_config,
252			genesis_build,
253			validate_unsigned,
254			error,
255			event,
256			origin,
257			inherent,
258			storages,
259			composites,
260			type_values,
261			frame_system,
262			frame_support,
263			dev_mode,
264			view_functions,
265			is_frame_system,
266		};
267
268		def.check_instance_usage()?;
269
270		Ok(def)
271	}
272
273	/// Performs extra logic checks necessary for the `#[pallet::tasks_experimental]` feature.
274	fn resolve_tasks(
275		item_span: &proc_macro2::Span,
276		tasks: &mut Option<tasks::TasksDef>,
277		task_enum: &mut Option<tasks::TaskEnumDef>,
278		items: &mut Vec<syn::Item>,
279	) -> syn::Result<()> {
280		// fallback for manual (without macros) definition of tasks impl
281		Self::resolve_manual_tasks_impl(tasks, task_enum, items)?;
282
283		// fallback for manual (without macros) definition of task enum
284		Self::resolve_manual_task_enum(tasks, task_enum, items)?;
285
286		// ensure that if `task_enum` is specified, `tasks` is also specified
287		match (&task_enum, &tasks) {
288			(Some(_), None) =>
289				return Err(syn::Error::new(
290					*item_span,
291					"Missing `#[pallet::tasks_experimental]` impl",
292				)),
293			(None, Some(tasks)) =>
294				if tasks.tasks_attr.is_none() {
295					return Err(syn::Error::new(
296						tasks.item_impl.impl_token.span(),
297						"A `#[pallet::tasks_experimental]` attribute must be attached to your `Task` impl if the \
298						task enum has been omitted",
299					));
300				} else {
301				},
302			_ => (),
303		}
304
305		Ok(())
306	}
307
308	/// Tries to locate task enum based on the tasks impl target if attribute is not specified
309	/// but impl is present. If one is found, `task_enum` is set appropriately.
310	fn resolve_manual_task_enum(
311		tasks: &Option<tasks::TasksDef>,
312		task_enum: &mut Option<tasks::TaskEnumDef>,
313		items: &mut Vec<syn::Item>,
314	) -> syn::Result<()> {
315		let (None, Some(tasks)) = (&task_enum, &tasks) else { return Ok(()) };
316		let syn::Type::Path(type_path) = &*tasks.item_impl.self_ty else { return Ok(()) };
317		let type_path = type_path.path.segments.iter().collect::<Vec<_>>();
318		let (Some(seg), None) = (type_path.get(0), type_path.get(1)) else { return Ok(()) };
319		let mut result = None;
320		for item in items {
321			let syn::Item::Enum(item_enum) = item else { continue };
322			if item_enum.ident == seg.ident {
323				result = Some(syn::parse2::<tasks::TaskEnumDef>(item_enum.to_token_stream())?);
324				// replace item with a no-op because it will be handled by the expansion of
325				// `task_enum`. We use a no-op instead of simply removing it from the vec
326				// so that any indices collected by `Def::try_from` remain accurate
327				*item = syn::Item::Verbatim(quote::quote!());
328				break;
329			}
330		}
331		*task_enum = result;
332		Ok(())
333	}
334
335	/// Tries to locate a manual tasks impl (an impl implementing a trait whose last path segment is
336	/// `Task`) in the event that one has not been found already via the attribute macro
337	pub fn resolve_manual_tasks_impl(
338		tasks: &mut Option<tasks::TasksDef>,
339		task_enum: &Option<tasks::TaskEnumDef>,
340		items: &Vec<syn::Item>,
341	) -> syn::Result<()> {
342		let None = tasks else { return Ok(()) };
343		let mut result = None;
344		for item in items {
345			let syn::Item::Impl(item_impl) = item else { continue };
346			let Some((_, path, _)) = &item_impl.trait_ else { continue };
347			let Some(trait_last_seg) = path.segments.last() else { continue };
348			let syn::Type::Path(target_path) = &*item_impl.self_ty else { continue };
349			let target_path = target_path.path.segments.iter().collect::<Vec<_>>();
350			let (Some(target_ident), None) = (target_path.get(0), target_path.get(1)) else {
351				continue;
352			};
353			let matches_task_enum = match task_enum {
354				Some(task_enum) => task_enum.item_enum.ident == target_ident.ident,
355				None => true,
356			};
357			if trait_last_seg.ident == "Task" && matches_task_enum {
358				result = Some(syn::parse2::<tasks::TasksDef>(item_impl.to_token_stream())?);
359				break;
360			}
361		}
362		*tasks = result;
363		Ok(())
364	}
365
366	/// Check that usage of trait `Config` is consistent with the definition, i.e. it is used with
367	/// instance iff it is defined with instance.
368	fn check_instance_usage(&self) -> syn::Result<()> {
369		let mut instances = vec![];
370		instances.extend_from_slice(&self.pallet_struct.instances[..]);
371		instances.extend(&mut self.storages.iter().flat_map(|s| s.instances.clone()));
372		if let Some(call) = &self.call {
373			instances.extend_from_slice(&call.instances[..]);
374		}
375		if let Some(hooks) = &self.hooks {
376			instances.extend_from_slice(&hooks.instances[..]);
377		}
378		if let Some(event) = &self.event {
379			instances.extend_from_slice(&event.instances[..]);
380		}
381		if let Some(error) = &self.error {
382			instances.extend_from_slice(&error.instances[..]);
383		}
384		if let Some(inherent) = &self.inherent {
385			instances.extend_from_slice(&inherent.instances[..]);
386		}
387		if let Some(origin) = &self.origin {
388			instances.extend_from_slice(&origin.instances[..]);
389		}
390		if let Some(genesis_config) = &self.genesis_config {
391			instances.extend_from_slice(&genesis_config.instances[..]);
392		}
393		if let Some(genesis_build) = &self.genesis_build {
394			genesis_build.instances.as_ref().map(|i| instances.extend_from_slice(&i));
395		}
396		if let Some(extra_constants) = &self.extra_constants {
397			instances.extend_from_slice(&extra_constants.instances[..]);
398		}
399		if let Some(task_enum) = &self.task_enum {
400			instances.push(task_enum.instance_usage.clone());
401		}
402
403		let mut errors = instances.into_iter().filter_map(|instances| {
404			if instances.has_instance == self.config.has_instance {
405				return None;
406			}
407			let msg = if self.config.has_instance {
408				"Invalid generic declaration, trait is defined with instance but generic use none"
409			} else {
410				"Invalid generic declaration, trait is defined without instance but generic use \
411						some"
412			};
413			Some(syn::Error::new(instances.span, msg))
414		});
415
416		if let Some(mut first_error) = errors.next() {
417			for error in errors {
418				first_error.combine(error)
419			}
420			Err(first_error)
421		} else {
422			Ok(())
423		}
424	}
425
426	/// Depending on if pallet is instantiable:
427	/// * either `T: Config`
428	/// * or `T: Config<I>, I: 'static`
429	pub fn type_impl_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
430		if self.config.has_instance {
431			quote::quote_spanned!(span => T: Config<I>, I: 'static)
432		} else {
433			quote::quote_spanned!(span => T: Config)
434		}
435	}
436
437	/// Depending on if pallet is instantiable:
438	/// * either `T: Config`
439	/// * or `T: Config<I>, I: 'static = ()`
440	pub fn type_decl_bounded_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
441		if self.config.has_instance {
442			quote::quote_spanned!(span => T: Config<I>, I: 'static = ())
443		} else {
444			quote::quote_spanned!(span => T: Config)
445		}
446	}
447
448	/// Depending on if pallet is instantiable:
449	/// * either `T`
450	/// * or `T, I = ()`
451	pub fn type_decl_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
452		if self.config.has_instance {
453			quote::quote_spanned!(span => T, I = ())
454		} else {
455			quote::quote_spanned!(span => T)
456		}
457	}
458
459	/// Depending on if pallet is instantiable:
460	/// * either ``
461	/// * or `<I>`
462	/// to be used when using pallet trait `Config`
463	pub fn trait_use_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
464		if self.config.has_instance {
465			quote::quote_spanned!(span => <I>)
466		} else {
467			quote::quote_spanned!(span => )
468		}
469	}
470
471	/// Depending on if pallet is instantiable:
472	/// * either `T`
473	/// * or `T, I`
474	pub fn type_use_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
475		if self.config.has_instance {
476			quote::quote_spanned!(span => T, I)
477		} else {
478			quote::quote_spanned!(span => T)
479		}
480	}
481}
482
483/// Some generic kind for type which can be not generic, or generic over config,
484/// or generic over config and instance, but not generic only over instance.
485pub enum GenericKind {
486	None,
487	Config,
488	ConfigAndInstance,
489}
490
491impl GenericKind {
492	/// Return Err if it is only generics over instance but not over config.
493	pub fn from_gens(has_config: bool, has_instance: bool) -> Result<Self, ()> {
494		match (has_config, has_instance) {
495			(false, false) => Ok(GenericKind::None),
496			(true, false) => Ok(GenericKind::Config),
497			(true, true) => Ok(GenericKind::ConfigAndInstance),
498			(false, true) => Err(()),
499		}
500	}
501
502	/// Return the generic to be used when using the type.
503	///
504	/// Depending on its definition it can be: ``, `T` or `T, I`
505	pub fn type_use_gen(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
506		match self {
507			GenericKind::None => quote::quote!(),
508			GenericKind::Config => quote::quote_spanned!(span => T),
509			GenericKind::ConfigAndInstance => quote::quote_spanned!(span => T, I),
510		}
511	}
512
513	/// Return the generic to be used in `impl<..>` when implementing on the type.
514	pub fn type_impl_gen(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
515		match self {
516			GenericKind::None => quote::quote!(),
517			GenericKind::Config => quote::quote_spanned!(span => T: Config),
518			GenericKind::ConfigAndInstance => {
519				quote::quote_spanned!(span => T: Config<I>, I: 'static)
520			},
521		}
522	}
523
524	/// Return whereas the type has some generic.
525	pub fn is_generic(&self) -> bool {
526		match self {
527			GenericKind::None => false,
528			GenericKind::Config | GenericKind::ConfigAndInstance => true,
529		}
530	}
531}
532
533/// List of additional token to be used for parsing.
534mod keyword {
535	syn::custom_keyword!(origin);
536	syn::custom_keyword!(call);
537	syn::custom_keyword!(tasks_experimental);
538	syn::custom_keyword!(task_enum);
539	syn::custom_keyword!(task_list);
540	syn::custom_keyword!(task_condition);
541	syn::custom_keyword!(task_index);
542	syn::custom_keyword!(weight);
543	syn::custom_keyword!(event);
544	syn::custom_keyword!(config);
545	syn::custom_keyword!(with_default);
546	syn::custom_keyword!(without_automatic_metadata);
547	syn::custom_keyword!(frame_system_config);
548	syn::custom_keyword!(hooks);
549	syn::custom_keyword!(inherent);
550	syn::custom_keyword!(error);
551	syn::custom_keyword!(storage);
552	syn::custom_keyword!(genesis_build);
553	syn::custom_keyword!(genesis_config);
554	syn::custom_keyword!(validate_unsigned);
555	syn::custom_keyword!(type_value);
556	syn::custom_keyword!(pallet);
557	syn::custom_keyword!(extra_constants);
558	syn::custom_keyword!(composite_enum);
559	syn::custom_keyword!(view_functions);
560}
561
562/// The possible values for the `#[pallet::config]` attribute.
563#[derive(Debug, Clone, PartialEq, Eq, Hash)]
564enum ConfigValue {
565	/// `#[pallet::config(with_default)]`
566	WithDefault(keyword::with_default),
567	/// `#[pallet::config(without_automatic_metadata)]`
568	WithoutAutomaticMetadata(keyword::without_automatic_metadata),
569	/// `#[pallet::config(frame_system_config)]`
570	FrameSystemConfig(keyword::frame_system_config),
571}
572
573impl syn::parse::Parse for ConfigValue {
574	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
575		let lookahead = input.lookahead1();
576
577		if lookahead.peek(keyword::with_default) {
578			input.parse().map(ConfigValue::WithDefault)
579		} else if lookahead.peek(keyword::without_automatic_metadata) {
580			input.parse().map(ConfigValue::WithoutAutomaticMetadata)
581		} else if lookahead.peek(keyword::frame_system_config) {
582			input.parse().map(ConfigValue::FrameSystemConfig)
583		} else {
584			Err(lookahead.error())
585		}
586	}
587}
588
589/// Parse attributes for item in pallet module
590/// syntax must be `pallet::` (e.g. `#[pallet::config]`)
591enum PalletAttr {
592	Config {
593		span: proc_macro2::Span,
594		with_default: bool,
595		without_automatic_metadata: bool,
596		frame_system_config: bool,
597	},
598	Pallet(proc_macro2::Span),
599	Hooks(proc_macro2::Span),
600	/// A `#[pallet::call]` with optional attributes to specialize the behaviour.
601	///
602	/// # Attributes
603	///
604	/// Each attribute `attr` can take the form of `#[pallet::call(attr = …)]` or
605	/// `#[pallet::call(attr(…))]`. The possible attributes are:
606	///
607	/// ## `weight`
608	///
609	/// Can be used to reduce the repetitive weight annotation in the trivial case. It accepts one
610	/// argument that is expected to be an implementation of the `WeightInfo` or something that
611	/// behaves syntactically equivalent. This allows to annotate a `WeightInfo` for all the calls.
612	/// Now each call does not need to specify its own `#[pallet::weight]` but can instead use the
613	/// one from the `#[pallet::call]` definition. So instead of having to write it on each call:
614	///
615	/// ```ignore
616	/// #[pallet::call]
617	/// impl<T: Config> Pallet<T> {
618	///     #[pallet::weight(T::WeightInfo::create())]
619	///     pub fn create(
620	/// ```
621	/// you can now omit it on the call itself, if the name of the weigh function matches the call:
622	///
623	/// ```ignore
624	/// #[pallet::call(weight = <T as crate::Config>::WeightInfo)]
625	/// impl<T: Config> Pallet<T> {
626	///     pub fn create(
627	/// ```
628	///
629	/// It is possible to use this syntax together with instantiated pallets by using `Config<I>`
630	/// instead.
631	///
632	/// ### Dev Mode
633	///
634	/// Normally the `dev_mode` sets all weights of calls without a `#[pallet::weight]` annotation
635	/// to zero. Now when there is a `weight` attribute on the `#[pallet::call]`, then that is used
636	/// instead of the zero weight. So to say: it works together with `dev_mode`.
637	RuntimeCall(Option<InheritedCallWeightAttr>, proc_macro2::Span),
638	Error(proc_macro2::Span),
639	Tasks(proc_macro2::Span),
640	TaskList(proc_macro2::Span),
641	TaskCondition(proc_macro2::Span),
642	TaskIndex(proc_macro2::Span),
643	RuntimeTask(proc_macro2::Span),
644	RuntimeEvent(proc_macro2::Span),
645	RuntimeOrigin(proc_macro2::Span),
646	Inherent(proc_macro2::Span),
647	Storage(proc_macro2::Span),
648	GenesisConfig(proc_macro2::Span),
649	GenesisBuild(proc_macro2::Span),
650	ValidateUnsigned(proc_macro2::Span),
651	TypeValue(proc_macro2::Span),
652	ExtraConstants(proc_macro2::Span),
653	Composite(proc_macro2::Span),
654	ViewFunctions(proc_macro2::Span),
655}
656
657impl PalletAttr {
658	fn span(&self) -> proc_macro2::Span {
659		match self {
660			Self::Config { span, .. } => *span,
661			Self::Pallet(span) => *span,
662			Self::Hooks(span) => *span,
663			Self::Tasks(span) => *span,
664			Self::TaskCondition(span) => *span,
665			Self::TaskIndex(span) => *span,
666			Self::TaskList(span) => *span,
667			Self::Error(span) => *span,
668			Self::RuntimeTask(span) => *span,
669			Self::RuntimeCall(_, span) => *span,
670			Self::RuntimeEvent(span) => *span,
671			Self::RuntimeOrigin(span) => *span,
672			Self::Inherent(span) => *span,
673			Self::Storage(span) => *span,
674			Self::GenesisConfig(span) => *span,
675			Self::GenesisBuild(span) => *span,
676			Self::ValidateUnsigned(span) => *span,
677			Self::TypeValue(span) => *span,
678			Self::ExtraConstants(span) => *span,
679			Self::Composite(span) => *span,
680			Self::ViewFunctions(span) => *span,
681		}
682	}
683}
684
685impl syn::parse::Parse for PalletAttr {
686	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
687		input.parse::<syn::Token![#]>()?;
688		let content;
689		syn::bracketed!(content in input);
690		content.parse::<keyword::pallet>()?;
691		content.parse::<syn::Token![::]>()?;
692
693		let lookahead = content.lookahead1();
694		if lookahead.peek(keyword::config) {
695			let span = content.parse::<keyword::config>()?.span();
696			if content.peek(syn::token::Paren) {
697				let inside_config;
698
699				// Parse (with_default, without_automatic_metadata) attributes.
700				let _paren = syn::parenthesized!(inside_config in content);
701
702				let fields: syn::punctuated::Punctuated<ConfigValue, syn::Token![,]> =
703					inside_config.parse_terminated(ConfigValue::parse, syn::Token![,])?;
704				let config_values = fields.iter().collect::<Vec<_>>();
705
706				let mut with_default = false;
707				let mut without_automatic_metadata = false;
708				let mut frame_system_config = false;
709				for config in config_values {
710					match config {
711						ConfigValue::WithDefault(_) => {
712							if with_default {
713								return Err(syn::Error::new(
714									span,
715									"Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: with_default.",
716								));
717							}
718							with_default = true;
719						},
720						ConfigValue::WithoutAutomaticMetadata(_) => {
721							if without_automatic_metadata {
722								return Err(syn::Error::new(
723									span,
724									"Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: without_automatic_metadata.",
725								));
726							}
727							without_automatic_metadata = true;
728						},
729						ConfigValue::FrameSystemConfig(_) => {
730							if frame_system_config {
731								return Err(syn::Error::new(
732									span,
733									"Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: frame_system_config.",
734								));
735							}
736							frame_system_config = true;
737						},
738					}
739				}
740
741				Ok(PalletAttr::Config {
742					span,
743					with_default,
744					without_automatic_metadata,
745					frame_system_config,
746				})
747			} else {
748				Ok(PalletAttr::Config {
749					span,
750					with_default: false,
751					without_automatic_metadata: false,
752					frame_system_config: false,
753				})
754			}
755		} else if lookahead.peek(keyword::pallet) {
756			Ok(PalletAttr::Pallet(content.parse::<keyword::pallet>()?.span()))
757		} else if lookahead.peek(keyword::hooks) {
758			Ok(PalletAttr::Hooks(content.parse::<keyword::hooks>()?.span()))
759		} else if lookahead.peek(keyword::call) {
760			let span = content.parse::<keyword::call>().expect("peeked").span();
761			let attr = match content.is_empty() {
762				true => None,
763				false => Some(InheritedCallWeightAttr::parse(&content)?),
764			};
765			Ok(PalletAttr::RuntimeCall(attr, span))
766		} else if lookahead.peek(keyword::tasks_experimental) {
767			Ok(PalletAttr::Tasks(content.parse::<keyword::tasks_experimental>()?.span()))
768		} else if lookahead.peek(keyword::task_enum) {
769			Ok(PalletAttr::RuntimeTask(content.parse::<keyword::task_enum>()?.span()))
770		} else if lookahead.peek(keyword::task_condition) {
771			Ok(PalletAttr::TaskCondition(content.parse::<keyword::task_condition>()?.span()))
772		} else if lookahead.peek(keyword::task_index) {
773			Ok(PalletAttr::TaskIndex(content.parse::<keyword::task_index>()?.span()))
774		} else if lookahead.peek(keyword::task_list) {
775			Ok(PalletAttr::TaskList(content.parse::<keyword::task_list>()?.span()))
776		} else if lookahead.peek(keyword::error) {
777			Ok(PalletAttr::Error(content.parse::<keyword::error>()?.span()))
778		} else if lookahead.peek(keyword::event) {
779			Ok(PalletAttr::RuntimeEvent(content.parse::<keyword::event>()?.span()))
780		} else if lookahead.peek(keyword::origin) {
781			Ok(PalletAttr::RuntimeOrigin(content.parse::<keyword::origin>()?.span()))
782		} else if lookahead.peek(keyword::inherent) {
783			Ok(PalletAttr::Inherent(content.parse::<keyword::inherent>()?.span()))
784		} else if lookahead.peek(keyword::storage) {
785			Ok(PalletAttr::Storage(content.parse::<keyword::storage>()?.span()))
786		} else if lookahead.peek(keyword::genesis_config) {
787			Ok(PalletAttr::GenesisConfig(content.parse::<keyword::genesis_config>()?.span()))
788		} else if lookahead.peek(keyword::genesis_build) {
789			Ok(PalletAttr::GenesisBuild(content.parse::<keyword::genesis_build>()?.span()))
790		} else if lookahead.peek(keyword::validate_unsigned) {
791			Ok(PalletAttr::ValidateUnsigned(content.parse::<keyword::validate_unsigned>()?.span()))
792		} else if lookahead.peek(keyword::type_value) {
793			Ok(PalletAttr::TypeValue(content.parse::<keyword::type_value>()?.span()))
794		} else if lookahead.peek(keyword::extra_constants) {
795			Ok(PalletAttr::ExtraConstants(content.parse::<keyword::extra_constants>()?.span()))
796		} else if lookahead.peek(keyword::composite_enum) {
797			Ok(PalletAttr::Composite(content.parse::<keyword::composite_enum>()?.span()))
798		} else if lookahead.peek(keyword::view_functions) {
799			Ok(PalletAttr::ViewFunctions(content.parse::<keyword::view_functions>()?.span()))
800		} else {
801			Err(lookahead.error())
802		}
803	}
804}
805
806/// The optional weight annotation on a `#[pallet::call]` like `#[pallet::call(weight($type))]`.
807#[derive(Clone)]
808pub struct InheritedCallWeightAttr {
809	pub typename: syn::Type,
810}
811
812impl syn::parse::Parse for InheritedCallWeightAttr {
813	// Parses `(weight($type))` or `(weight = $type)`.
814	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
815		let content;
816		syn::parenthesized!(content in input);
817		content.parse::<keyword::weight>()?;
818		let lookahead = content.lookahead1();
819
820		let buffer = if lookahead.peek(syn::token::Paren) {
821			let inner;
822			syn::parenthesized!(inner in content);
823			inner
824		} else if lookahead.peek(syn::Token![=]) {
825			content.parse::<syn::Token![=]>().expect("peeked");
826			content
827		} else {
828			return Err(lookahead.error());
829		};
830
831		Ok(Self { typename: buffer.parse()? })
832	}
833}