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