sway_core/language/ty/declaration/
enum.rs

1use crate::{
2    decl_engine::MaterializeConstGenerics,
3    engine_threading::*,
4    has_changes,
5    language::{parsed::EnumDeclaration, ty::TyDeclParsedType, CallPath, Visibility},
6    transform,
7    type_system::*,
8};
9use ast_elements::type_parameter::ConstGenericExpr;
10use monomorphization::MonomorphizeHelper;
11use serde::{Deserialize, Serialize};
12use std::{
13    cmp::Ordering,
14    hash::{Hash, Hasher},
15};
16use sway_error::{
17    error::CompileError,
18    handler::{ErrorEmitted, Handler},
19};
20use sway_types::{Ident, Named, Span, Spanned};
21
22#[derive(Clone, Debug, Serialize, Deserialize)]
23pub struct TyEnumDecl {
24    pub call_path: CallPath,
25    pub generic_parameters: Vec<TypeParameter>,
26    pub attributes: transform::Attributes,
27    pub variants: Vec<TyEnumVariant>,
28    pub span: Span,
29    pub visibility: Visibility,
30}
31
32impl TyDeclParsedType for TyEnumDecl {
33    type ParsedType = EnumDeclaration;
34}
35
36impl Named for TyEnumDecl {
37    fn name(&self) -> &Ident {
38        &self.call_path.suffix
39    }
40}
41
42impl EqWithEngines for TyEnumDecl {}
43impl PartialEqWithEngines for TyEnumDecl {
44    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
45        self.call_path == other.call_path
46            && self.generic_parameters.eq(&other.generic_parameters, ctx)
47            && self.variants.eq(&other.variants, ctx)
48            && self.visibility == other.visibility
49    }
50}
51
52impl HashWithEngines for TyEnumDecl {
53    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
54        let TyEnumDecl {
55            call_path,
56            generic_parameters: type_parameters,
57            variants,
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        variants.hash(state, engines);
66        type_parameters.hash(state, engines);
67        visibility.hash(state);
68    }
69}
70
71impl SubstTypes for TyEnumDecl {
72    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
73        has_changes! {
74            self.variants.subst(ctx);
75            self.generic_parameters.subst(ctx);
76        }
77    }
78}
79
80impl Spanned for TyEnumDecl {
81    fn span(&self) -> Span {
82        self.span.clone()
83    }
84}
85
86impl IsConcrete for TyEnumDecl {
87    fn is_concrete(&self, engines: &Engines) -> bool {
88        self.generic_parameters
89            .iter()
90            .all(|tp| tp.is_concrete(engines))
91    }
92}
93
94impl MonomorphizeHelper for TyEnumDecl {
95    fn type_parameters(&self) -> &[TypeParameter] {
96        &self.generic_parameters
97    }
98
99    fn name(&self) -> &Ident {
100        &self.call_path.suffix
101    }
102
103    fn has_self_type_param(&self) -> bool {
104        false
105    }
106}
107
108impl MaterializeConstGenerics for TyEnumDecl {
109    fn materialize_const_generics(
110        &mut self,
111        engines: &Engines,
112        handler: &Handler,
113        name: &str,
114        value: &crate::language::ty::TyExpression,
115    ) -> Result<(), ErrorEmitted> {
116        for p in self.generic_parameters.iter_mut() {
117            match p {
118                TypeParameter::Const(p) if p.name.as_str() == name => {
119                    p.expr = Some(ConstGenericExpr::from_ty_expression(handler, value)?);
120                }
121                TypeParameter::Type(p) => {
122                    p.type_id
123                        .materialize_const_generics(engines, handler, name, value)?;
124                }
125                _ => {}
126            }
127        }
128
129        for variant in self.variants.iter_mut() {
130            variant
131                .type_argument
132                .type_id_mut()
133                .materialize_const_generics(engines, handler, name, value)?;
134        }
135
136        Ok(())
137    }
138}
139
140impl TyEnumDecl {
141    pub(crate) fn expect_variant_from_name(
142        &self,
143        handler: &Handler,
144        variant_name: &Ident,
145    ) -> Result<&TyEnumVariant, ErrorEmitted> {
146        match self
147            .variants
148            .iter()
149            .find(|x| x.name.as_str() == variant_name.as_str())
150        {
151            Some(variant) => Ok(variant),
152            None => Err(handler.emit_err(CompileError::UnknownEnumVariant {
153                enum_name: self.call_path.suffix.clone(),
154                variant_name: variant_name.clone(),
155                span: variant_name.span(),
156            })),
157        }
158    }
159}
160
161impl Spanned for TyEnumVariant {
162    fn span(&self) -> Span {
163        self.span.clone()
164    }
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct TyEnumVariant {
169    pub name: Ident,
170    pub type_argument: GenericArgument,
171    pub(crate) tag: usize,
172    pub span: Span,
173    pub attributes: transform::Attributes,
174}
175
176impl HashWithEngines for TyEnumVariant {
177    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
178        self.name.hash(state);
179        self.type_argument.hash(state, engines);
180        self.tag.hash(state);
181    }
182}
183
184impl EqWithEngines for TyEnumVariant {}
185impl PartialEqWithEngines for TyEnumVariant {
186    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
187        self.name == other.name
188            && self.type_argument.eq(&other.type_argument, ctx)
189            && self.tag == other.tag
190    }
191}
192
193impl OrdWithEngines for TyEnumVariant {
194    fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
195        let TyEnumVariant {
196            name: ln,
197            type_argument: lta,
198            tag: lt,
199            // these fields are not compared because they aren't relevant/a
200            // reliable source of obj v. obj distinction
201            span: _,
202            attributes: _,
203        } = self;
204        let TyEnumVariant {
205            name: rn,
206            type_argument: rta,
207            tag: rt,
208            // these fields are not compared because they aren't relevant/a
209            // reliable source of obj v. obj distinction
210            span: _,
211            attributes: _,
212        } = other;
213        ln.cmp(rn)
214            .then_with(|| lta.cmp(rta, ctx))
215            .then_with(|| lt.cmp(rt))
216    }
217}
218
219impl SubstTypes for TyEnumVariant {
220    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
221        self.type_argument.subst_inner(ctx)
222    }
223}