sway_core/language/ty/declaration/
storage.rs

1use crate::{
2    engine_threading::*,
3    ir_generation::storage::get_storage_key_string,
4    language::parsed::StorageDeclaration,
5    transform::{self},
6    ty::*,
7    type_system::*,
8    Namespace,
9};
10use serde::{Deserialize, Serialize};
11use std::hash::{Hash, Hasher};
12use sway_error::{
13    error::{CompileError, StructFieldUsageContext},
14    handler::{ErrorEmitted, Handler},
15};
16use sway_types::{Ident, Named, Span, Spanned};
17
18#[derive(Clone, Debug, Serialize, Deserialize)]
19pub struct TyStorageDecl {
20    pub fields: Vec<TyStorageField>,
21    pub span: Span,
22    pub attributes: transform::Attributes,
23    pub storage_keyword: Ident,
24}
25
26impl TyDeclParsedType for TyStorageDecl {
27    type ParsedType = StorageDeclaration;
28}
29
30impl Named for TyStorageDecl {
31    fn name(&self) -> &Ident {
32        &self.storage_keyword
33    }
34}
35
36impl EqWithEngines for TyStorageDecl {}
37impl PartialEqWithEngines for TyStorageDecl {
38    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
39        self.fields.eq(&other.fields, ctx) && self.attributes == other.attributes
40    }
41}
42
43impl HashWithEngines for TyStorageDecl {
44    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
45        let TyStorageDecl {
46            fields,
47            // these fields are not hashed because they aren't relevant/a
48            // reliable source of obj v. obj distinction
49            span: _,
50            attributes: _,
51            storage_keyword: _,
52        } = self;
53        fields.hash(state, engines);
54    }
55}
56
57impl Spanned for TyStorageDecl {
58    fn span(&self) -> Span {
59        self.span.clone()
60    }
61}
62
63impl TyStorageDecl {
64    /// Given a path that consists of `fields`, where the first field is one of the storage fields,
65    /// find the type information of all the elements in the path and return it as a [TyStorageAccess].
66    ///
67    /// The first element in the `fields` must be one of the storage fields.
68    /// The last element in the `fields` can, but must not be, a struct.
69    /// All the elements in between must be structs.
70    ///
71    /// An error is returned if the above constraints are violated or if the access to the struct fields
72    /// fails. E.g, if the struct field does not exists or is an inaccessible private field.
73    #[allow(clippy::too_many_arguments)]
74    pub fn apply_storage_load(
75        &self,
76        handler: &Handler,
77        engines: &Engines,
78        namespace: &Namespace,
79        namespace_names: &[Ident],
80        fields: &[Ident],
81        storage_fields: &[TyStorageField],
82        storage_keyword_span: Span,
83    ) -> Result<(TyStorageAccess, TypeId), ErrorEmitted> {
84        let type_engine = engines.te();
85        let decl_engine = engines.de();
86
87        // The resulting storage access descriptors, built on the go as we move through the `fields`.
88        let mut access_descriptors = vec![];
89        // The field we've analyzed before the current field we are on, and its type id.
90        let mut previous_field: &Ident;
91        let mut previous_field_type_id: TypeId;
92
93        let (first_field, remaining_fields) = fields.split_first().expect(
94            "Having at least one element in the storage load is guaranteed by the grammar.",
95        );
96
97        let (initial_field_type, initial_field_key, initial_field_name) =
98            match storage_fields.iter().find(|sf| {
99                &sf.name == first_field
100                    && sf.namespace_names.len() == namespace_names.len()
101                    && sf
102                        .namespace_names
103                        .iter()
104                        .zip(namespace_names.iter())
105                        .all(|(n1, n2)| n1 == n2)
106            }) {
107                Some(TyStorageField {
108                    type_argument,
109                    key_expression,
110                    name,
111                    ..
112                }) => (type_argument.type_id(), key_expression, name),
113                None => {
114                    return Err(handler.emit_err(CompileError::StorageFieldDoesNotExist {
115                        field_name: first_field.into(),
116                        available_fields: storage_fields
117                            .iter()
118                            .map(|sf| (sf.namespace_names.clone(), sf.name.clone()))
119                            .collect(),
120                        storage_decl_span: self.span(),
121                    }));
122                }
123            };
124
125        access_descriptors.push(TyStorageAccessDescriptor {
126            name: first_field.clone(),
127            type_id: initial_field_type,
128            span: first_field.span(),
129        });
130
131        previous_field = first_field;
132        previous_field_type_id = initial_field_type;
133
134        // Storage cannot contain references, so there is no need for checking
135        // if the declaration is a reference to a struct. References can still
136        // be erroneously declared in the storage, and the type behind a concrete
137        // field access might be a reference to struct, but we do not treat that
138        // as a special case but just another one "not a struct".
139        // The FieldAccessOnNonStruct error message will explain that in the case
140        // of storage access, fields can be accessed only on structs.
141        let get_struct_decl = |type_id: TypeId| match &*type_engine.get(type_id) {
142            TypeInfo::Struct(decl_ref) => Some(decl_engine.get_struct(decl_ref)),
143            _ => None,
144        };
145
146        let mut struct_field_names = vec![];
147
148        for field in remaining_fields {
149            match get_struct_decl(previous_field_type_id) {
150                Some(struct_decl) => {
151                    let (struct_can_be_changed, is_public_struct_access) =
152                        StructAccessInfo::get_info(engines, &struct_decl, namespace).into();
153
154                    match struct_decl.find_field(field) {
155                        Some(struct_field) => {
156                            if is_public_struct_access && struct_field.is_private() {
157                                return Err(handler.emit_err(CompileError::StructFieldIsPrivate {
158                                    field_name: field.into(),
159                                    struct_name: struct_decl.call_path.suffix.clone(),
160                                    field_decl_span: struct_field.name.span(),
161                                    struct_can_be_changed,
162                                    usage_context: StructFieldUsageContext::StorageAccess,
163                                }));
164                            }
165
166                            // Everything is fine. Push the storage access descriptor and move to the next field.
167
168                            let current_field_type_id = struct_field.type_argument.type_id();
169
170                            access_descriptors.push(TyStorageAccessDescriptor {
171                                name: field.clone(),
172                                type_id: current_field_type_id,
173                                span: field.span(),
174                            });
175
176                            struct_field_names.push(field.as_str().to_string());
177
178                            previous_field = field;
179                            previous_field_type_id = current_field_type_id;
180                        }
181                        None => {
182                            // Since storage cannot be passed to other modules, the access
183                            // is always in the module of the storage declaration.
184                            // If the struct cannot be instantiated in this module at all,
185                            // we will just show the error, without any additional help lines
186                            // showing available fields or anything.
187                            // Note that if the struct is empty it can always be instantiated.
188                            let struct_can_be_instantiated =
189                                !is_public_struct_access || !struct_decl.has_private_fields();
190
191                            let available_fields = if struct_can_be_instantiated {
192                                struct_decl.accessible_fields_names(is_public_struct_access)
193                            } else {
194                                vec![]
195                            };
196
197                            return Err(handler.emit_err(CompileError::StructFieldDoesNotExist {
198                                field_name: field.into(),
199                                available_fields,
200                                is_public_struct_access,
201                                struct_name: struct_decl.call_path.suffix.clone(),
202                                struct_decl_span: struct_decl.span(),
203                                struct_is_empty: struct_decl.is_empty(),
204                                usage_context: StructFieldUsageContext::StorageAccess,
205                            }));
206                        }
207                    }
208                }
209                None => {
210                    return Err(handler.emit_err(CompileError::FieldAccessOnNonStruct {
211                        actually: engines.help_out(previous_field_type_id).to_string(),
212                        storage_variable: Some(previous_field.to_string()),
213                        field_name: field.into(),
214                        span: previous_field.span(),
215                    }))
216                }
217            };
218        }
219
220        let return_type = access_descriptors[access_descriptors.len() - 1].type_id;
221
222        Ok((
223            TyStorageAccess {
224                fields: access_descriptors,
225                key_expression: initial_field_key.clone().map(Box::new),
226                storage_field_names: namespace_names
227                    .iter()
228                    .map(|n| n.as_str().to_string())
229                    .chain(vec![initial_field_name.as_str().to_string()])
230                    .collect(),
231                struct_field_names,
232                storage_keyword_span,
233            },
234            return_type,
235        ))
236    }
237}
238
239impl Spanned for TyStorageField {
240    fn span(&self) -> Span {
241        self.span.clone()
242    }
243}
244
245#[derive(Clone, Debug, Serialize, Deserialize)]
246pub struct TyStorageField {
247    pub name: Ident,
248    pub namespace_names: Vec<Ident>,
249    pub key_expression: Option<TyExpression>,
250    pub type_argument: GenericArgument,
251    pub initializer: TyExpression,
252    pub(crate) span: Span,
253    pub attributes: transform::Attributes,
254}
255
256impl TyStorageField {
257    /// Returns the full name of the [TyStorageField], consisting
258    /// of its name preceded by its full namespace path.
259    /// E.g., "storage::ns1::ns1.name".
260    pub fn full_name(&self) -> String {
261        get_storage_key_string(
262            &self
263                .namespace_names
264                .iter()
265                .map(|i| i.as_str().to_string())
266                .chain(vec![self.name.as_str().to_string()])
267                .collect::<Vec<_>>(),
268        )
269    }
270}
271
272impl EqWithEngines for TyStorageField {}
273impl PartialEqWithEngines for TyStorageField {
274    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
275        self.name == other.name
276            && self.namespace_names.eq(&other.namespace_names)
277            && self.type_argument.eq(&other.type_argument, ctx)
278            && self.initializer.eq(&other.initializer, ctx)
279    }
280}
281
282impl HashWithEngines for TyStorageField {
283    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
284        let TyStorageField {
285            name,
286            namespace_names,
287            key_expression,
288            type_argument,
289            initializer,
290            // these fields are not hashed because they aren't relevant/a
291            // reliable source of obj v. obj distinction
292            span: _,
293            attributes: _,
294        } = self;
295        name.hash(state);
296        namespace_names.hash(state);
297        key_expression.hash(state, engines);
298        type_argument.hash(state, engines);
299        initializer.hash(state, engines);
300    }
301}