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 monomorphization::MonomorphizeHelper;
14use serde::{Deserialize, Serialize};
15use std::{
16    cmp::Ordering,
17    hash::{Hash, Hasher},
18};
19use sway_error::handler::{ErrorEmitted, Handler};
20use sway_types::{Ident, Named, Span, Spanned};
21
22#[derive(Clone, Debug, Serialize, Deserialize)]
23pub struct TyStructDecl {
24    pub call_path: CallPath,
25    pub fields: Vec<TyStructField>,
26    pub type_parameters: Vec<TypeParameter>,
27    pub visibility: Visibility,
28    pub span: Span,
29    pub attributes: transform::Attributes,
30}
31
32impl TyDeclParsedType for TyStructDecl {
33    type ParsedType = StructDeclaration;
34}
35
36impl Named for TyStructDecl {
37    fn name(&self) -> &Ident {
38        &self.call_path.suffix
39    }
40}
41
42impl EqWithEngines for TyStructDecl {}
43impl PartialEqWithEngines for TyStructDecl {
44    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
45        self.call_path == other.call_path
46            && self.fields.eq(&other.fields, ctx)
47            && self.type_parameters.eq(&other.type_parameters, ctx)
48            && self.visibility == other.visibility
49    }
50}
51
52impl HashWithEngines for TyStructDecl {
53    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
54        let TyStructDecl {
55            call_path,
56            fields,
57            type_parameters,
58            visibility,
59            // these fields are not hashed because they aren't relevant/a
60            // reliable source of obj v. obj distinction
61            span: _,
62            attributes: _,
63        } = self;
64        call_path.hash(state);
65        fields.hash(state, engines);
66        type_parameters.hash(state, engines);
67        visibility.hash(state);
68    }
69}
70
71impl SubstTypes for TyStructDecl {
72    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
73        has_changes! {
74            self.fields.subst(ctx);
75            self.type_parameters.subst(ctx);
76        }
77    }
78}
79
80impl Spanned for TyStructDecl {
81    fn span(&self) -> Span {
82        self.span.clone()
83    }
84}
85
86impl MonomorphizeHelper for TyStructDecl {
87    fn type_parameters(&self) -> &[TypeParameter] {
88        &self.type_parameters
89    }
90
91    fn name(&self) -> &Ident {
92        &self.call_path.suffix
93    }
94
95    fn has_self_type_param(&self) -> bool {
96        false
97    }
98}
99
100impl MaterializeConstGenerics for TyStructDecl {
101    fn materialize_const_generics(
102        &mut self,
103        _engines: &Engines,
104        _handler: &Handler,
105        _name: &str,
106        _value: &crate::language::ty::TyExpression,
107    ) -> Result<(), ErrorEmitted> {
108        Ok(())
109    }
110}
111
112impl TyStructDecl {
113    /// Returns names of the [TyStructField]s of the struct `self` accessible in the given context.
114    /// If `is_public_struct_access` is true, only the names of the public fields are returned, otherwise
115    /// the names of all fields.
116    /// Suitable for error reporting.
117    pub(crate) fn accessible_fields_names(&self, is_public_struct_access: bool) -> Vec<Ident> {
118        TyStructField::accessible_fields_names(&self.fields, is_public_struct_access)
119    }
120
121    /// Returns [TyStructField] with the given `field_name`, or `None` if the field with the
122    /// name `field_name` does not exist.
123    pub(crate) fn find_field(&self, field_name: &Ident) -> Option<&TyStructField> {
124        self.fields.iter().find(|field| field.name == *field_name)
125    }
126
127    /// For the given `field_name` returns the zero-based index and the type of the field
128    /// within the struct memory layout, or `None` if the field with the
129    /// name `field_name` does not exist.
130    pub(crate) fn get_field_index_and_type(&self, field_name: &Ident) -> Option<(u64, TypeId)> {
131        // TODO-MEMLAY: Warning! This implementation assumes that fields are laid out in
132        //              memory in the order of their declaration.
133        //              This assumption can be changed in the future.
134        self.fields
135            .iter()
136            .enumerate()
137            .find(|(_, field)| field.name == *field_name)
138            .map(|(idx, field)| (idx as u64, field.type_argument.type_id()))
139    }
140
141    /// Returns true if the struct `self` has at least one private field.
142    pub(crate) fn has_private_fields(&self) -> bool {
143        self.fields.iter().any(|field| field.is_private())
144    }
145
146    /// Returns true if the struct `self` has fields (it is not empty)
147    /// and all fields are private.
148    pub(crate) fn has_only_private_fields(&self) -> bool {
149        !self.is_empty() && self.fields.iter().all(|field| field.is_private())
150    }
151
152    /// Returns true if the struct `self` does not have any fields.
153    pub(crate) fn is_empty(&self) -> bool {
154        self.fields.is_empty()
155    }
156}
157
158/// Provides information about the struct access within a particular [Namespace].
159pub struct StructAccessInfo {
160    /// True if the programmer who can change the code in the [Namespace]
161    /// can also change the struct declaration.
162    struct_can_be_changed: bool,
163    /// True if the struct access is public, i.e., outside of the module in
164    /// which the struct is defined.
165    is_public_struct_access: bool,
166}
167
168impl StructAccessInfo {
169    pub fn get_info(engines: &Engines, struct_decl: &TyStructDecl, namespace: &Namespace) -> Self {
170        assert!(
171            matches!(struct_decl.call_path.callpath_type, CallPathType::Full),
172            "The call path of the struct declaration must always be fully resolved."
173        );
174
175        let struct_can_be_changed =
176            module_can_be_changed(engines, namespace, &struct_decl.call_path.prefixes);
177        let is_public_struct_access =
178            !namespace.module_is_submodule_of(&struct_decl.call_path.prefixes, true);
179
180        Self {
181            struct_can_be_changed,
182            is_public_struct_access,
183        }
184    }
185}
186
187impl From<StructAccessInfo> for (bool, bool) {
188    /// Deconstructs `struct_access_info` into (`struct_can_be_changed`, `is_public_struct_access`)
189    fn from(struct_access_info: StructAccessInfo) -> (bool, bool) {
190        let StructAccessInfo {
191            struct_can_be_changed,
192            is_public_struct_access,
193        } = struct_access_info;
194        (struct_can_be_changed, is_public_struct_access)
195    }
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct TyStructField {
200    pub visibility: Visibility,
201    pub name: Ident,
202    pub span: Span,
203    pub type_argument: GenericArgument,
204    pub attributes: transform::Attributes,
205}
206
207impl TyStructField {
208    pub fn is_private(&self) -> bool {
209        matches!(self.visibility, Visibility::Private)
210    }
211
212    pub fn is_public(&self) -> bool {
213        matches!(self.visibility, Visibility::Public)
214    }
215
216    /// Returns [TyStructField]s from the `fields` that are accessible in the given context.
217    /// If `is_public_struct_access` is true, only public fields are returned, otherwise
218    /// all fields.
219    pub(crate) fn accessible_fields(
220        fields: &[TyStructField],
221        is_public_struct_access: bool,
222    ) -> impl Iterator<Item = &TyStructField> {
223        fields
224            .iter()
225            .filter(move |field| !is_public_struct_access || field.is_public())
226    }
227
228    /// Returns names of the [TyStructField]s from the `fields` that are accessible in the given context.
229    /// If `is_public_struct_access` is true, only the names of the public fields are returned, otherwise
230    /// the names of all fields.
231    /// Suitable for error reporting.
232    pub(crate) fn accessible_fields_names(
233        fields: &[TyStructField],
234        is_public_struct_access: bool,
235    ) -> Vec<Ident> {
236        Self::accessible_fields(fields, is_public_struct_access)
237            .map(|field| field.name.clone())
238            .collect()
239    }
240}
241
242impl Spanned for TyStructField {
243    fn span(&self) -> Span {
244        self.span.clone()
245    }
246}
247
248impl HashWithEngines for TyStructField {
249    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
250        let TyStructField {
251            visibility,
252            name,
253            type_argument,
254            // these fields are not hashed because they aren't relevant/a
255            // reliable source of obj v. obj distinction
256            span: _,
257            attributes: _,
258        } = self;
259        visibility.hash(state);
260        name.hash(state);
261        type_argument.hash(state, engines);
262    }
263}
264
265impl EqWithEngines for TyStructField {}
266impl PartialEqWithEngines for TyStructField {
267    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
268        self.name == other.name && self.type_argument.eq(&other.type_argument, ctx)
269    }
270}
271
272impl OrdWithEngines for TyStructField {
273    fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
274        let TyStructField {
275            name: ln,
276            type_argument: lta,
277            // these fields are not compared because they aren't relevant for ordering
278            span: _,
279            attributes: _,
280            visibility: _,
281        } = self;
282        let TyStructField {
283            name: rn,
284            type_argument: rta,
285            // these fields are not compared because they aren't relevant for ordering
286            span: _,
287            attributes: _,
288            visibility: _,
289        } = other;
290        ln.cmp(rn).then_with(|| lta.cmp(rta, ctx))
291    }
292}
293
294impl SubstTypes for TyStructField {
295    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
296        self.type_argument.subst_inner(ctx)
297    }
298}