scale_typegen/typegen/
error.rs

1use std::collections::HashSet;
2
3use proc_macro2::Span;
4use quote::ToTokens;
5
6/// Error for when something went wrong during type generation.
7#[derive(Debug, thiserror::Error)]
8#[non_exhaustive]
9pub enum TypegenError {
10    /// Could not parse into a syn type.
11    #[error("Could not parse into a syn type: {0}")]
12    SynParseError(#[from] syn::Error),
13    /// Fields should either be all named or all unnamed, make sure you are providing a valid metadata.
14    #[error("Fields should either be all named or all unnamed, make sure you are providing a valid metadata: {0}")]
15    InvalidFields(String),
16    /// A type in the metadata was invalid
17    #[error("A type in the metadata was invalid: {0}")]
18    InvalidType(String),
19    /// Could not generate a type that contains a compact type, because the Compact type path is not set in the settings.
20    #[error("Could not generate a type that contains a compact type, because the Compact type path is not set in the settings.")]
21    CompactPathNone,
22    /// Could not generate a type that contains a bit sequence, because the DecodedBits type path is not set in the settings.
23    #[error("Could not generate a type that contains a bit sequence, because the DecodedBits type path is not set in the settings.")]
24    DecodedBitsPathNone,
25    /// Could not find type with ID in the type registry.
26    #[error("Could not find type with ID {0} in the type registry.")]
27    TypeNotFound(u32),
28    /// Type substitution error.
29    #[error("Type substitution error: {0}")]
30    InvalidSubstitute(#[from] TypeSubstitutionError),
31    /// The settings do not fit the given type registry.
32    #[error("Settings do not fit the given type registry: {0}")]
33    SettingsValidation(SettingsValidationError),
34    /// There are two types with the the same type path but a different structure.
35    /// Use [`crate::utils::ensure_unique_type_paths`] on your [`scale_info::PortableRegistry`] to deduplicate type paths.
36    #[error("There are two types with the the same type path {0} but different structure. Use `scale_typegen::utils::ensure_unique_type_paths` on your `PortableRegistry` before, to avoid this error.")]
37    DuplicateTypePath(String),
38    /// PortableRegistry entry has incorrect Id.
39    #[error("PortableRegistry entry has incorrect type_id. expected type_id: {expected_ty_id}, got: {given_ty_id}.\nDefinition of the type: {ty_def}.\nThis can happen if registry was modified with calls to `::retain()` in older versions of scale-info. Try generating a new metadata to fix this.")]
40    RegistryTypeIdsInvalid {
41        /// Received type id
42        given_ty_id: u32,
43        /// Expected type id
44        expected_ty_id: u32,
45        /// Type definition
46        ty_def: String,
47    },
48}
49
50/// Error attempting to do type substitution.
51#[derive(Debug, thiserror::Error)]
52pub struct TypeSubstitutionError {
53    /// Where in the code the error occured.
54    pub span: Span,
55    /// Kind of TypeSubstitutionError that happended.
56    pub kind: TypeSubstitutionErrorKind,
57}
58
59impl std::fmt::Display for TypeSubstitutionError {
60    fn fmt(
61        &self,
62        f: &mut scale_info::prelude::fmt::Formatter<'_>,
63    ) -> scale_info::prelude::fmt::Result {
64        f.write_fmt(format_args!("{}", self.kind))
65    }
66}
67
68/// Error attempting to do type substitution.
69#[derive(Debug, thiserror::Error)]
70#[non_exhaustive]
71pub enum TypeSubstitutionErrorKind {
72    /// Substitute "to" type must be an absolute path.
73    #[error("`substitute_type(with = <path>)` must be a path prefixed with 'crate::' or '::'")]
74    ExpectedAbsolutePath,
75    /// Substitute types must have a valid path.
76    #[error("Substitute types must have a valid path.")]
77    EmptySubstitutePath,
78    /// From/To substitution types should use angle bracket generics.
79    #[error("Expected the from/to type generics to have the form 'Foo<A,B,C..>'.")]
80    ExpectedAngleBracketGenerics,
81    /// Source substitute type must be an ident.
82    #[error("Expected an ident like 'Foo' or 'A' to mark a type to be substituted.")]
83    InvalidFromType,
84    /// Target type is invalid.
85    #[error("Expected an ident like 'Foo' or an absolute concrete path like '::path::to::Bar' for the substitute type.")]
86    InvalidToType,
87    /// Target ident doesn't correspond to any source type.
88    #[error("Cannot find matching param on 'from' type.")]
89    NoMatchingFromType,
90}
91
92/// Error attempting to do type substitution.
93#[derive(Debug, thiserror::Error, Default, PartialEq, Eq)]
94pub struct SettingsValidationError {
95    /// Cannot add derive for type that is not present in the registry.
96    pub derives_for_unknown_types: Vec<(syn::Path, HashSet<syn::Path>)>,
97    /// Cannot add attribute for type that is not present in the registry.
98    pub attributes_for_unknown_types: Vec<(syn::Path, HashSet<syn::Attribute>)>,
99    /// Invalid path to replace: the type getting substituted is not present in the registry.
100    pub substitutes_for_unknown_types: Vec<(syn::Path, syn::Path)>,
101}
102
103impl std::fmt::Display for SettingsValidationError {
104    fn fmt(
105        &self,
106        f: &mut scale_info::prelude::fmt::Formatter<'_>,
107    ) -> scale_info::prelude::fmt::Result {
108        fn display_one(e: &impl ToTokens) -> String {
109            e.to_token_stream().to_string().replace(' ', "")
110        }
111
112        fn display_many(set: &HashSet<impl ToTokens>) -> String {
113            set.iter()
114                .map(|e| display_one(e))
115                .collect::<Vec<_>>()
116                .join(", ")
117        }
118
119        writeln!(f, "Settings validation error:")?;
120
121        if !self.derives_for_unknown_types.is_empty() {
122            writeln!(f, "  Derives for unknown types:")?;
123            for (path, derives) in &self.derives_for_unknown_types {
124                writeln!(
125                    f,
126                    "    {} (Derives: {})",
127                    display_one(path),
128                    display_many(derives)
129                )?;
130            }
131        }
132
133        if !self.attributes_for_unknown_types.is_empty() {
134            writeln!(f, "  Attributes for unknown types:")?;
135            for (path, attributes) in &self.attributes_for_unknown_types {
136                writeln!(
137                    f,
138                    "    {} (Attributes: {})",
139                    display_one(path),
140                    display_many(attributes)
141                )?;
142            }
143        }
144
145        if !self.substitutes_for_unknown_types.is_empty() {
146            writeln!(f, "  Substitutes for unknown types:")?;
147            for (original, substitute) in &self.substitutes_for_unknown_types {
148                writeln!(
149                    f,
150                    "    {} (Substitute: {})",
151                    display_one(original),
152                    display_one(substitute),
153                )?;
154            }
155        }
156
157        Ok(())
158    }
159}
160
161impl SettingsValidationError {
162    pub(crate) fn is_empty(&self) -> bool {
163        self.derives_for_unknown_types.is_empty()
164            && self.attributes_for_unknown_types.is_empty()
165            && self.substitutes_for_unknown_types.is_empty()
166    }
167}