sway_core/language/ty/declaration/
struct.rs1use crate::{
2 ast_elements::type_argument::GenericTypeArgument,
3 decl_engine::MaterializeConstGenerics,
4 engine_threading::*,
5 error::module_can_be_changed,
6 has_changes,
7 language::{
8 parsed::StructDeclaration, ty::TyDeclParsedType, CallPath, CallPathType, Visibility,
9 },
10 transform,
11 type_system::*,
12 HasChanges, Namespace,
13};
14use ast_elements::type_parameter::ConstGenericExpr;
15use monomorphization::MonomorphizeHelper;
16use serde::{Deserialize, Serialize};
17use std::{
18 cmp::Ordering,
19 hash::{Hash, Hasher},
20};
21use sway_error::handler::{ErrorEmitted, Handler};
22use sway_types::{Ident, Named, Span, Spanned};
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
25pub struct TyStructDecl {
26 pub call_path: CallPath,
27 pub fields: Vec<TyStructField>,
28 pub generic_parameters: Vec<TypeParameter>,
29 pub visibility: Visibility,
30 pub span: Span,
31 pub attributes: transform::Attributes,
32}
33
34impl TyDeclParsedType for TyStructDecl {
35 type ParsedType = StructDeclaration;
36}
37
38impl Named for TyStructDecl {
39 fn name(&self) -> &Ident {
40 &self.call_path.suffix
41 }
42}
43
44impl EqWithEngines for TyStructDecl {}
45impl PartialEqWithEngines for TyStructDecl {
46 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
47 self.call_path == other.call_path
48 && self.fields.eq(&other.fields, ctx)
49 && self.generic_parameters.eq(&other.generic_parameters, ctx)
50 && self.visibility == other.visibility
51 }
52}
53
54impl HashWithEngines for TyStructDecl {
55 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
56 let TyStructDecl {
57 call_path,
58 fields,
59 generic_parameters: type_parameters,
60 visibility,
61 span: _,
64 attributes: _,
65 } = self;
66 call_path.hash(state);
67 fields.hash(state, engines);
68 type_parameters.hash(state, engines);
69 visibility.hash(state);
70 }
71}
72
73impl SubstTypes for TyStructDecl {
74 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
75 has_changes! {
76 self.fields.subst(ctx);
77 self.generic_parameters.subst(ctx);
78 }
79 }
80}
81
82impl Spanned for TyStructDecl {
83 fn span(&self) -> Span {
84 self.span.clone()
85 }
86}
87
88impl MonomorphizeHelper for TyStructDecl {
89 fn type_parameters(&self) -> &[TypeParameter] {
90 &self.generic_parameters
91 }
92
93 fn name(&self) -> &Ident {
94 &self.call_path.suffix
95 }
96
97 fn has_self_type_param(&self) -> bool {
98 false
99 }
100}
101
102impl MaterializeConstGenerics for TyStructDecl {
103 fn materialize_const_generics(
104 &mut self,
105 engines: &Engines,
106 handler: &Handler,
107 name: &str,
108 value: &crate::language::ty::TyExpression,
109 ) -> Result<HasChanges, ErrorEmitted> {
110 let mut has_changes = HasChanges::No;
111 for p in self.generic_parameters.iter_mut() {
112 match p {
113 TypeParameter::Const(p) if p.name.as_str() == name => {
114 p.expr = Some(ConstGenericExpr::from_ty_expression(handler, value)?);
115 has_changes = HasChanges::Yes;
116 }
117 _ => {}
118 }
119 }
120
121 for field in self.fields.iter_mut() {
122 has_changes |= field
123 .type_argument
124 .type_id
125 .materialize_const_generics(engines, handler, name, value)?;
126 }
127
128 Ok(has_changes)
129 }
130}
131
132impl TyStructDecl {
133 pub(crate) fn accessible_fields_names(&self, is_public_struct_access: bool) -> Vec<Ident> {
138 TyStructField::accessible_fields_names(&self.fields, is_public_struct_access)
139 }
140
141 pub(crate) fn find_field(&self, field_name: &Ident) -> Option<&TyStructField> {
144 self.fields.iter().find(|field| field.name == *field_name)
145 }
146
147 pub(crate) fn get_field_index_and_type(&self, field_name: &Ident) -> Option<(u64, TypeId)> {
151 self.fields
155 .iter()
156 .enumerate()
157 .find(|(_, field)| field.name == *field_name)
158 .map(|(idx, field)| (idx as u64, field.type_argument.type_id))
159 }
160
161 pub(crate) fn has_private_fields(&self) -> bool {
163 self.fields.iter().any(|field| field.is_private())
164 }
165
166 pub(crate) fn has_only_private_fields(&self) -> bool {
169 !self.is_empty() && self.fields.iter().all(|field| field.is_private())
170 }
171
172 pub(crate) fn is_empty(&self) -> bool {
174 self.fields.is_empty()
175 }
176}
177
178pub struct StructAccessInfo {
180 struct_can_be_changed: bool,
183 is_public_struct_access: bool,
186}
187
188impl StructAccessInfo {
189 pub fn get_info(engines: &Engines, struct_decl: &TyStructDecl, namespace: &Namespace) -> Self {
190 assert!(
191 matches!(struct_decl.call_path.callpath_type, CallPathType::Full),
192 "The call path of the struct declaration must always be fully resolved."
193 );
194
195 let struct_can_be_changed =
196 module_can_be_changed(engines, namespace, &struct_decl.call_path.prefixes);
197 let is_public_struct_access =
198 !namespace.module_is_submodule_of(&struct_decl.call_path.prefixes, true);
199
200 Self {
201 struct_can_be_changed,
202 is_public_struct_access,
203 }
204 }
205}
206
207impl From<StructAccessInfo> for (bool, bool) {
208 fn from(struct_access_info: StructAccessInfo) -> (bool, bool) {
210 let StructAccessInfo {
211 struct_can_be_changed,
212 is_public_struct_access,
213 } = struct_access_info;
214 (struct_can_be_changed, is_public_struct_access)
215 }
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize)]
219pub struct TyStructField {
220 pub visibility: Visibility,
221 pub name: Ident,
222 pub span: Span,
223 pub type_argument: GenericTypeArgument,
224 pub attributes: transform::Attributes,
225}
226
227impl TyStructField {
228 pub fn is_private(&self) -> bool {
229 matches!(self.visibility, Visibility::Private)
230 }
231
232 pub fn is_public(&self) -> bool {
233 matches!(self.visibility, Visibility::Public)
234 }
235
236 pub(crate) fn accessible_fields(
240 fields: &[TyStructField],
241 is_public_struct_access: bool,
242 ) -> impl Iterator<Item = &TyStructField> {
243 fields
244 .iter()
245 .filter(move |field| !is_public_struct_access || field.is_public())
246 }
247
248 pub(crate) fn accessible_fields_names(
253 fields: &[TyStructField],
254 is_public_struct_access: bool,
255 ) -> Vec<Ident> {
256 Self::accessible_fields(fields, is_public_struct_access)
257 .map(|field| field.name.clone())
258 .collect()
259 }
260}
261
262impl Spanned for TyStructField {
263 fn span(&self) -> Span {
264 self.span.clone()
265 }
266}
267
268impl HashWithEngines for TyStructField {
269 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
270 let TyStructField {
271 visibility,
272 name,
273 type_argument,
274 span: _,
277 attributes: _,
278 } = self;
279 visibility.hash(state);
280 name.hash(state);
281 type_argument.hash(state, engines);
282 }
283}
284
285impl EqWithEngines for TyStructField {}
286impl PartialEqWithEngines for TyStructField {
287 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
288 self.name == other.name && self.type_argument.eq(&other.type_argument, ctx)
289 }
290}
291
292impl OrdWithEngines for TyStructField {
293 fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
294 let TyStructField {
295 name: ln,
296 type_argument: lta,
297 span: _,
299 attributes: _,
300 visibility: _,
301 } = self;
302 let TyStructField {
303 name: rn,
304 type_argument: rta,
305 span: _,
307 attributes: _,
308 visibility: _,
309 } = other;
310 ln.cmp(rn).then_with(|| lta.cmp(rta, ctx))
311 }
312}
313
314impl SubstTypes for TyStructField {
315 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
316 self.type_argument.subst_inner(ctx)
317 }
318}