Skip to main content

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