sway_core/language/ty/declaration/
storage.rs1use 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 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 #[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 let mut access_descriptors = vec![];
89 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 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 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 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 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 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}