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