sway_core/language/ty/declaration/
struct.rs

1use 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            // these fields are not hashed because they aren't relevant/a
61            // reliable source of obj v. obj distinction
62            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    /// Returns names of the [TyStructField]s of the struct `self` accessible in the given context.
131    /// If `is_public_struct_access` is true, only the names of the public fields are returned, otherwise
132    /// the names of all fields.
133    /// Suitable for error reporting.
134    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    /// Returns [TyStructField] with the given `field_name`, or `None` if the field with the
139    /// name `field_name` does not exist.
140    pub(crate) fn find_field(&self, field_name: &Ident) -> Option<&TyStructField> {
141        self.fields.iter().find(|field| field.name == *field_name)
142    }
143
144    /// For the given `field_name` returns the zero-based index and the type of the field
145    /// within the struct memory layout, or `None` if the field with the
146    /// name `field_name` does not exist.
147    pub(crate) fn get_field_index_and_type(&self, field_name: &Ident) -> Option<(u64, TypeId)> {
148        // TODO-MEMLAY: Warning! This implementation assumes that fields are laid out in
149        //              memory in the order of their declaration.
150        //              This assumption can be changed in the future.
151        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    /// Returns true if the struct `self` has at least one private field.
159    pub(crate) fn has_private_fields(&self) -> bool {
160        self.fields.iter().any(|field| field.is_private())
161    }
162
163    /// Returns true if the struct `self` has fields (it is not empty)
164    /// and all fields are private.
165    pub(crate) fn has_only_private_fields(&self) -> bool {
166        !self.is_empty() && self.fields.iter().all(|field| field.is_private())
167    }
168
169    /// Returns true if the struct `self` does not have any fields.
170    pub(crate) fn is_empty(&self) -> bool {
171        self.fields.is_empty()
172    }
173}
174
175/// Provides information about the struct access within a particular [Namespace].
176pub struct StructAccessInfo {
177    /// True if the programmer who can change the code in the [Namespace]
178    /// can also change the struct declaration.
179    struct_can_be_changed: bool,
180    /// True if the struct access is public, i.e., outside of the module in
181    /// which the struct is defined.
182    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    /// Deconstructs `struct_access_info` into (`struct_can_be_changed`, `is_public_struct_access`)
206    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    /// Returns [TyStructField]s from the `fields` that are accessible in the given context.
234    /// If `is_public_struct_access` is true, only public fields are returned, otherwise
235    /// all fields.
236    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    /// Returns names of the [TyStructField]s from the `fields` that are accessible in the given context.
246    /// If `is_public_struct_access` is true, only the names of the public fields are returned, otherwise
247    /// the names of all fields.
248    /// Suitable for error reporting.
249    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            // these fields are not hashed because they aren't relevant/a
272            // reliable source of obj v. obj distinction
273            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            // these fields are not compared because they aren't relevant for ordering
295            span: _,
296            attributes: _,
297            visibility: _,
298        } = self;
299        let TyStructField {
300            name: rn,
301            type_argument: rta,
302            // these fields are not compared because they aren't relevant for ordering
303            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}