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)]
78 pub fn apply_storage_access(
79 &self,
80 handler: &Handler,
81 engines: &Engines,
82 namespace: &Namespace,
83 namespace_names: &[Ident],
84 field_names: &[Ident],
85 storage_fields: &[TyStorageField],
86 storage_keyword_span: Span,
87 ) -> Result<(TyStorageAccess, TypeId), ErrorEmitted> {
88 let type_engine = engines.te();
89 let decl_engine = engines.de();
90
91 let mut access_descriptors = vec![];
93 let mut previous_field: &Ident;
95 let mut previous_field_type_id: TypeId;
96
97 let (first_field, remaining_fields) = field_names.split_first().expect(
98 "Having at least one element in a storage access is guaranteed by the grammar.",
99 );
100
101 let (initial_field_type, initial_field_key, initial_field_name) =
102 match storage_fields.iter().find(|sf| {
103 &sf.name == first_field
104 && sf.namespace_names.len() == namespace_names.len()
105 && sf
106 .namespace_names
107 .iter()
108 .zip(namespace_names.iter())
109 .all(|(n1, n2)| n1 == n2)
110 }) {
111 Some(TyStorageField {
112 type_argument,
113 key_expression,
114 name,
115 ..
116 }) => (type_argument.type_id, key_expression, name),
117 None => {
118 return Err(handler.emit_err(CompileError::StorageFieldDoesNotExist {
119 field_name: first_field.into(),
120 available_fields: storage_fields
121 .iter()
122 .map(|sf| (sf.namespace_names.clone(), sf.name.clone()))
123 .collect(),
124 storage_decl_span: self.span(),
125 }));
126 }
127 };
128
129 access_descriptors.push(TyStorageAccessDescriptor {
130 name: first_field.clone(),
131 type_id: initial_field_type,
132 span: first_field.span(),
133 });
134
135 previous_field = first_field;
136 previous_field_type_id = initial_field_type;
137
138 let get_struct_decl = |type_id: TypeId| match &*type_engine.get(type_id) {
146 TypeInfo::Struct(decl_ref) => Some(decl_engine.get_struct(decl_ref)),
147 _ => None,
148 };
149
150 let mut struct_field_names = vec![];
151
152 for field in remaining_fields {
153 match get_struct_decl(previous_field_type_id) {
154 Some(struct_decl) => {
155 let (struct_can_be_changed, is_public_struct_access) =
156 StructAccessInfo::get_info(engines, &struct_decl, namespace).into();
157
158 match struct_decl.find_field(field) {
159 Some(struct_field) => {
160 if is_public_struct_access && struct_field.is_private() {
161 return Err(handler.emit_err(CompileError::StructFieldIsPrivate {
162 field_name: field.into(),
163 struct_name: struct_decl.call_path.suffix.clone(),
164 field_decl_span: struct_field.name.span(),
165 struct_can_be_changed,
166 usage_context: StructFieldUsageContext::StorageAccess,
167 }));
168 }
169
170 let current_field_type_id = struct_field.type_argument.type_id;
173
174 access_descriptors.push(TyStorageAccessDescriptor {
175 name: field.clone(),
176 type_id: current_field_type_id,
177 span: field.span(),
178 });
179
180 struct_field_names.push(field.as_str().to_string());
181
182 previous_field = field;
183 previous_field_type_id = current_field_type_id;
184 }
185 None => {
186 let struct_can_be_instantiated =
193 !is_public_struct_access || !struct_decl.has_private_fields();
194
195 let available_fields = if struct_can_be_instantiated {
196 struct_decl.accessible_fields_names(is_public_struct_access)
197 } else {
198 vec![]
199 };
200
201 return Err(handler.emit_err(CompileError::StructFieldDoesNotExist {
202 field_name: field.into(),
203 available_fields,
204 is_public_struct_access,
205 struct_name: struct_decl.call_path.suffix.clone(),
206 struct_decl_span: struct_decl.span(),
207 struct_is_empty: struct_decl.is_empty(),
208 usage_context: StructFieldUsageContext::StorageAccess,
209 }));
210 }
211 }
212 }
213 None => {
214 return Err(handler.emit_err(CompileError::FieldAccessOnNonStruct {
215 actually: engines.help_out(previous_field_type_id).to_string(),
216 storage_variable: Some(previous_field.to_string()),
217 field_name: field.into(),
218 span: previous_field.span(),
219 }))
220 }
221 };
222 }
223
224 let return_type = access_descriptors[access_descriptors.len() - 1].type_id;
225
226 Ok((
227 TyStorageAccess {
228 fields: access_descriptors,
229 key_expression: initial_field_key.clone().map(Box::new),
230 storage_field_path: namespace_names
231 .iter()
232 .map(|n| n.as_str().to_string())
233 .chain(vec![initial_field_name.as_str().to_string()])
234 .collect(),
235 struct_field_names,
236 storage_keyword_span,
237 },
238 return_type,
239 ))
240 }
241}
242
243impl Spanned for TyStorageField {
244 fn span(&self) -> Span {
245 self.span.clone()
246 }
247}
248
249#[derive(Clone, Debug, Serialize, Deserialize)]
250pub struct TyStorageField {
251 pub name: Ident,
252 pub namespace_names: Vec<Ident>,
253 pub key_expression: Option<TyExpression>,
254 pub type_argument: GenericTypeArgument,
255 pub initializer: TyExpression,
256 pub(crate) span: Span,
257 pub attributes: transform::Attributes,
258}
259
260impl TyStorageField {
261 pub fn full_name(&self) -> String {
266 get_storage_key_string(&self.path())
267 }
268
269 pub fn path(&self) -> Vec<String> {
273 self.namespace_names
274 .iter()
275 .map(|ns_name| ns_name.as_str().to_string())
276 .chain(std::iter::once(self.name.as_str().to_string()))
277 .collect()
278 }
279}
280
281impl EqWithEngines for TyStorageField {}
282impl PartialEqWithEngines for TyStorageField {
283 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
284 self.name == other.name
285 && self.namespace_names.eq(&other.namespace_names)
286 && self.type_argument.eq(&other.type_argument, ctx)
287 && self.initializer.eq(&other.initializer, ctx)
288 }
289}
290
291impl HashWithEngines for TyStorageField {
292 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
293 let TyStorageField {
294 name,
295 namespace_names,
296 key_expression,
297 type_argument,
298 initializer,
299 span: _,
302 attributes: _,
303 } = self;
304 name.hash(state);
305 namespace_names.hash(state);
306 key_expression.hash(state, engines);
307 type_argument.hash(state, engines);
308 initializer.hash(state, engines);
309 }
310}