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 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<(), ErrorEmitted> {
110 for p in self.generic_parameters.iter_mut() {
111 match p {
112 TypeParameter::Const(p) if p.name.as_str() == name => {
113 p.expr = Some(ConstGenericExpr::from_ty_expression(handler, value)?);
114 }
115 _ => {}
116 }
117 }
118
119 for field in self.fields.iter_mut() {
120 field
121 .type_argument
122 .type_id
123 .materialize_const_generics(engines, handler, name, value)?;
124 }
125
126 Ok(())
127 }
128}
129
130impl TyStructDecl {
131 pub(crate) fn accessible_fields_names(&self, is_public_struct_access: bool) -> Vec<Ident> {
136 TyStructField::accessible_fields_names(&self.fields, is_public_struct_access)
137 }
138
139 pub(crate) fn find_field(&self, field_name: &Ident) -> Option<&TyStructField> {
142 self.fields.iter().find(|field| field.name == *field_name)
143 }
144
145 pub(crate) fn get_field_index_and_type(&self, field_name: &Ident) -> Option<(u64, TypeId)> {
149 self.fields
153 .iter()
154 .enumerate()
155 .find(|(_, field)| field.name == *field_name)
156 .map(|(idx, field)| (idx as u64, field.type_argument.type_id))
157 }
158
159 pub(crate) fn has_private_fields(&self) -> bool {
161 self.fields.iter().any(|field| field.is_private())
162 }
163
164 pub(crate) fn has_only_private_fields(&self) -> bool {
167 !self.is_empty() && self.fields.iter().all(|field| field.is_private())
168 }
169
170 pub(crate) fn is_empty(&self) -> bool {
172 self.fields.is_empty()
173 }
174}
175
176pub struct StructAccessInfo {
178 struct_can_be_changed: bool,
181 is_public_struct_access: bool,
184}
185
186impl StructAccessInfo {
187 pub fn get_info(engines: &Engines, struct_decl: &TyStructDecl, namespace: &Namespace) -> Self {
188 assert!(
189 matches!(struct_decl.call_path.callpath_type, CallPathType::Full),
190 "The call path of the struct declaration must always be fully resolved."
191 );
192
193 let struct_can_be_changed =
194 module_can_be_changed(engines, namespace, &struct_decl.call_path.prefixes);
195 let is_public_struct_access =
196 !namespace.module_is_submodule_of(&struct_decl.call_path.prefixes, true);
197
198 Self {
199 struct_can_be_changed,
200 is_public_struct_access,
201 }
202 }
203}
204
205impl From<StructAccessInfo> for (bool, bool) {
206 fn from(struct_access_info: StructAccessInfo) -> (bool, bool) {
208 let StructAccessInfo {
209 struct_can_be_changed,
210 is_public_struct_access,
211 } = struct_access_info;
212 (struct_can_be_changed, is_public_struct_access)
213 }
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct TyStructField {
218 pub visibility: Visibility,
219 pub name: Ident,
220 pub span: Span,
221 pub type_argument: GenericTypeArgument,
222 pub attributes: transform::Attributes,
223}
224
225impl TyStructField {
226 pub fn is_private(&self) -> bool {
227 matches!(self.visibility, Visibility::Private)
228 }
229
230 pub fn is_public(&self) -> bool {
231 matches!(self.visibility, Visibility::Public)
232 }
233
234 pub(crate) fn accessible_fields(
238 fields: &[TyStructField],
239 is_public_struct_access: bool,
240 ) -> impl Iterator<Item = &TyStructField> {
241 fields
242 .iter()
243 .filter(move |field| !is_public_struct_access || field.is_public())
244 }
245
246 pub(crate) fn accessible_fields_names(
251 fields: &[TyStructField],
252 is_public_struct_access: bool,
253 ) -> Vec<Ident> {
254 Self::accessible_fields(fields, is_public_struct_access)
255 .map(|field| field.name.clone())
256 .collect()
257 }
258}
259
260impl Spanned for TyStructField {
261 fn span(&self) -> Span {
262 self.span.clone()
263 }
264}
265
266impl HashWithEngines for TyStructField {
267 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
268 let TyStructField {
269 visibility,
270 name,
271 type_argument,
272 span: _,
275 attributes: _,
276 } = self;
277 visibility.hash(state);
278 name.hash(state);
279 type_argument.hash(state, engines);
280 }
281}
282
283impl EqWithEngines for TyStructField {}
284impl PartialEqWithEngines for TyStructField {
285 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
286 self.name == other.name && self.type_argument.eq(&other.type_argument, ctx)
287 }
288}
289
290impl OrdWithEngines for TyStructField {
291 fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
292 let TyStructField {
293 name: ln,
294 type_argument: lta,
295 span: _,
297 attributes: _,
298 visibility: _,
299 } = self;
300 let TyStructField {
301 name: rn,
302 type_argument: rta,
303 span: _,
305 attributes: _,
306 visibility: _,
307 } = other;
308 ln.cmp(rn).then_with(|| lta.cmp(rta, ctx))
309 }
310}
311
312impl SubstTypes for TyStructField {
313 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
314 self.type_argument.subst_inner(ctx)
315 }
316}