sway_core/language/ty/declaration/
enum.rs

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