sway_core/language/ty/
ast_node.rs

1use crate::{
2    decl_engine::*,
3    engine_threading::*,
4    language::ty::*,
5    semantic_analysis::{
6        TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization,
7        TypeCheckFinalizationContext,
8    },
9    transform::{AllowDeprecatedState, AttributeKind},
10    type_system::*,
11    types::*,
12};
13use serde::{Deserialize, Serialize};
14use std::{
15    fmt::{self, Debug},
16    hash::{Hash, Hasher},
17};
18use sway_error::handler::{ErrorEmitted, Handler};
19use sway_types::{Ident, Span};
20
21pub trait GetDeclIdent {
22    fn get_decl_ident(&self, engines: &Engines) -> Option<Ident>;
23}
24
25#[derive(Clone, Debug, Serialize, Deserialize)]
26pub struct TyAstNode {
27    pub content: TyAstNodeContent,
28    pub span: Span,
29}
30
31impl EqWithEngines for TyAstNode {}
32impl PartialEqWithEngines for TyAstNode {
33    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
34        self.content.eq(&other.content, ctx)
35    }
36}
37
38impl HashWithEngines for TyAstNode {
39    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
40        let TyAstNode {
41            content,
42            // the span is not hashed because it isn't relevant/a reliable
43            // source of obj v. obj distinction
44            span: _,
45        } = self;
46        content.hash(state, engines);
47    }
48}
49
50impl DebugWithEngines for TyAstNode {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
52        use TyAstNodeContent::*;
53        match &self.content {
54            Declaration(typed_decl) => DebugWithEngines::fmt(typed_decl, f, engines),
55            Expression(exp) => DebugWithEngines::fmt(exp, f, engines),
56            SideEffect(_) => f.write_str(""),
57            Error(_, _) => f.write_str("error"),
58        }
59    }
60}
61
62impl SubstTypes for TyAstNode {
63    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
64        match self.content {
65            TyAstNodeContent::Declaration(ref mut decl) => decl.subst(ctx),
66            TyAstNodeContent::Expression(ref mut expr) => expr.subst(ctx),
67            TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => HasChanges::No,
68        }
69    }
70}
71
72impl ReplaceDecls for TyAstNode {
73    fn replace_decls_inner(
74        &mut self,
75        decl_mapping: &DeclMapping,
76        handler: &Handler,
77        ctx: &mut TypeCheckContext,
78    ) -> Result<bool, ErrorEmitted> {
79        match self.content {
80            TyAstNodeContent::Declaration(TyDecl::VariableDecl(ref mut decl)) => {
81                decl.body.replace_decls(decl_mapping, handler, ctx)
82            }
83            TyAstNodeContent::Declaration(_) => Ok(false),
84            TyAstNodeContent::Expression(ref mut expr) => {
85                expr.replace_decls(decl_mapping, handler, ctx)
86            }
87            TyAstNodeContent::SideEffect(_) => Ok(false),
88            TyAstNodeContent::Error(_, _) => Ok(false),
89        }
90    }
91}
92
93impl UpdateConstantExpression for TyAstNode {
94    fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
95        match self.content {
96            TyAstNodeContent::Declaration(_) => {}
97            TyAstNodeContent::Expression(ref mut expr) => {
98                expr.update_constant_expression(engines, implementing_type)
99            }
100            TyAstNodeContent::SideEffect(_) => (),
101            TyAstNodeContent::Error(_, _) => (),
102        }
103    }
104}
105
106impl TypeCheckAnalysis for TyAstNode {
107    fn type_check_analyze(
108        &self,
109        handler: &Handler,
110        ctx: &mut TypeCheckAnalysisContext,
111    ) -> Result<(), ErrorEmitted> {
112        self.content.type_check_analyze(handler, ctx)
113    }
114}
115
116impl TypeCheckFinalization for TyAstNode {
117    fn type_check_finalize(
118        &mut self,
119        handler: &Handler,
120        ctx: &mut TypeCheckFinalizationContext,
121    ) -> Result<(), ErrorEmitted> {
122        self.content.type_check_finalize(handler, ctx)
123    }
124}
125
126impl CollectTypesMetadata for TyAstNode {
127    fn collect_types_metadata(
128        &self,
129        handler: &Handler,
130        ctx: &mut CollectTypesMetadataContext,
131    ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
132        self.content.collect_types_metadata(handler, ctx)
133    }
134}
135
136impl GetDeclIdent for TyAstNode {
137    fn get_decl_ident(&self, engines: &Engines) -> Option<Ident> {
138        self.content.get_decl_ident(engines)
139    }
140}
141
142impl MaterializeConstGenerics for TyAstNode {
143    fn materialize_const_generics(
144        &mut self,
145        engines: &Engines,
146        handler: &Handler,
147        name: &str,
148        value: &TyExpression,
149    ) -> Result<(), ErrorEmitted> {
150        match self.content {
151            TyAstNodeContent::Declaration(_) => Ok(()),
152            TyAstNodeContent::Expression(ref mut expr) => {
153                expr.materialize_const_generics(engines, handler, name, value)
154            }
155            TyAstNodeContent::SideEffect(_) => Ok(()),
156            TyAstNodeContent::Error(_, _) => Ok(()),
157        }
158    }
159}
160
161impl TyAstNode {
162    /// Returns `true` if this AST node will be exported in a library, i.e. it is a public declaration.
163    pub(crate) fn is_public(&self, decl_engine: &DeclEngine) -> bool {
164        match &self.content {
165            TyAstNodeContent::Declaration(decl) => decl.visibility(decl_engine).is_public(),
166            TyAstNodeContent::Expression(_)
167            | TyAstNodeContent::SideEffect(_)
168            | TyAstNodeContent::Error(_, _) => false,
169        }
170    }
171
172    /// Check to see if this node is a function declaration with generic type parameters.
173    pub(crate) fn is_generic_function(&self, decl_engine: &DeclEngine) -> bool {
174        match &self {
175            TyAstNode {
176                span: _,
177                content:
178                    TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl {
179                        decl_id, ..
180                    })),
181                ..
182            } => {
183                let fn_decl = decl_engine.get_function(decl_id);
184                let TyFunctionDecl {
185                    type_parameters, ..
186                } = &*fn_decl;
187                !type_parameters.is_empty()
188            }
189            _ => false,
190        }
191    }
192
193    /// Check to see if this node is a function declaration of a function annotated as test.
194    pub(crate) fn is_test_function(&self, decl_engine: &DeclEngine) -> bool {
195        match &self {
196            TyAstNode {
197                span: _,
198                content:
199                    TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl {
200                        decl_id, ..
201                    })),
202                ..
203            } => {
204                let fn_decl = decl_engine.get_function(decl_id);
205                let TyFunctionDecl { attributes, .. } = &*fn_decl;
206                attributes.contains_key(&AttributeKind::Test)
207            }
208            _ => false,
209        }
210    }
211
212    pub(crate) fn type_info(&self, type_engine: &TypeEngine) -> TypeInfo {
213        // return statement should be ()
214        match &self.content {
215            TyAstNodeContent::Declaration(_) => TypeInfo::Tuple(Vec::new()),
216            TyAstNodeContent::Expression(TyExpression { return_type, .. }) => {
217                (*type_engine.get(*return_type)).clone()
218            }
219            TyAstNodeContent::SideEffect(_) => TypeInfo::Tuple(Vec::new()),
220            TyAstNodeContent::Error(_, error) => TypeInfo::ErrorRecovery(*error),
221        }
222    }
223
224    pub(crate) fn check_deprecated(
225        &self,
226        engines: &Engines,
227        handler: &Handler,
228        allow_deprecated: &mut AllowDeprecatedState,
229    ) {
230        match &self.content {
231            TyAstNodeContent::Declaration(node) => match node {
232                TyDecl::VariableDecl(decl) => {
233                    decl.body
234                        .check_deprecated(engines, handler, allow_deprecated);
235                }
236                TyDecl::ConstantDecl(decl) => {
237                    let decl = engines.de().get(&decl.decl_id);
238                    if let Some(value) = &decl.value {
239                        value.check_deprecated(engines, handler, allow_deprecated);
240                    }
241                }
242                TyDecl::ConfigurableDecl(decl) => {
243                    let decl = engines.de().get(&decl.decl_id);
244                    if let Some(value) = &decl.value {
245                        value.check_deprecated(engines, handler, allow_deprecated);
246                    }
247                }
248                TyDecl::ConstGenericDecl(_) => {
249                    todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
250                }
251                TyDecl::TraitTypeDecl(_) => {}
252                TyDecl::FunctionDecl(decl) => {
253                    let decl = engines.de().get(&decl.decl_id);
254                    let token = allow_deprecated.enter(decl.attributes.clone());
255                    for node in decl.body.contents.iter() {
256                        node.check_deprecated(engines, handler, allow_deprecated);
257                    }
258                    allow_deprecated.exit(token);
259                }
260                TyDecl::ImplSelfOrTrait(decl) => {
261                    let decl = engines.de().get(&decl.decl_id);
262                    for item in decl.items.iter() {
263                        match item {
264                            TyTraitItem::Fn(item) => {
265                                let decl = engines.de().get(item.id());
266                                let token = allow_deprecated.enter(decl.attributes.clone());
267                                for node in decl.body.contents.iter() {
268                                    node.check_deprecated(engines, handler, allow_deprecated);
269                                }
270                                allow_deprecated.exit(token);
271                            }
272                            TyTraitItem::Constant(item) => {
273                                let decl = engines.de().get(item.id());
274                                if let Some(expr) = decl.value.as_ref() {
275                                    expr.check_deprecated(engines, handler, allow_deprecated);
276                                }
277                            }
278                            TyTraitItem::Type(_) => {}
279                        }
280                    }
281                }
282                TyDecl::AbiDecl(_)
283                | TyDecl::GenericTypeForFunctionScope(_)
284                | TyDecl::ErrorRecovery(_, _)
285                | TyDecl::StorageDecl(_)
286                | TyDecl::TraitDecl(_)
287                | TyDecl::StructDecl(_)
288                | TyDecl::EnumDecl(_)
289                | TyDecl::EnumVariantDecl(_)
290                | TyDecl::TypeAliasDecl(_) => {}
291            },
292            TyAstNodeContent::Expression(node) => {
293                node.check_deprecated(engines, handler, allow_deprecated);
294            }
295            TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {}
296        }
297    }
298
299    pub(crate) fn check_recursive(
300        &self,
301        engines: &Engines,
302        handler: &Handler,
303    ) -> Result<(), ErrorEmitted> {
304        handler.scope(|handler| {
305            match &self.content {
306                TyAstNodeContent::Declaration(node) => match node {
307                    TyDecl::VariableDecl(_decl) => {}
308                    TyDecl::ConstantDecl(_decl) => {}
309                    TyDecl::ConfigurableDecl(_decl) => {}
310                    TyDecl::ConstGenericDecl(_decl) => {
311                        todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
312                    }
313                    TyDecl::TraitTypeDecl(_) => {}
314                    TyDecl::FunctionDecl(decl) => {
315                        let fn_decl_id = decl.decl_id;
316                        let mut ctx = TypeCheckAnalysisContext::new(engines);
317                        let _ = fn_decl_id.type_check_analyze(handler, &mut ctx);
318                        let _ = ctx.check_recursive_calls(handler);
319                    }
320                    TyDecl::ImplSelfOrTrait(decl) => {
321                        let decl = engines.de().get(&decl.decl_id);
322                        for item in decl.items.iter() {
323                            let mut ctx = TypeCheckAnalysisContext::new(engines);
324                            let _ = item.type_check_analyze(handler, &mut ctx);
325                            let _ = ctx.check_recursive_calls(handler);
326                        }
327                    }
328                    TyDecl::AbiDecl(_)
329                    | TyDecl::GenericTypeForFunctionScope(_)
330                    | TyDecl::ErrorRecovery(_, _)
331                    | TyDecl::StorageDecl(_)
332                    | TyDecl::TraitDecl(_)
333                    | TyDecl::StructDecl(_)
334                    | TyDecl::EnumDecl(_)
335                    | TyDecl::EnumVariantDecl(_)
336                    | TyDecl::TypeAliasDecl(_) => {}
337                },
338                TyAstNodeContent::Expression(_node) => {}
339                TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {}
340            };
341            Ok(())
342        })
343    }
344
345    pub fn contract_supertrait_fns(&self, engines: &Engines) -> Vec<DeclId<TyFunctionDecl>> {
346        let mut fns = vec![];
347
348        if let TyAstNodeContent::Declaration(TyDecl::ImplSelfOrTrait(decl)) = &self.content {
349            let decl = engines.de().get(&decl.decl_id);
350            if decl.is_impl_contract(engines.te()) {
351                for item in &decl.supertrait_items {
352                    if let TyTraitItem::Fn(f) = item {
353                        fns.push(*f.id());
354                    }
355                }
356            }
357        }
358
359        fns
360    }
361
362    pub fn contract_fns(&self, engines: &Engines) -> Vec<DeclId<TyFunctionDecl>> {
363        let mut fns = vec![];
364
365        if let TyAstNodeContent::Declaration(TyDecl::ImplSelfOrTrait(decl)) = &self.content {
366            let decl = engines.de().get(&decl.decl_id);
367            if decl.is_impl_contract(engines.te()) {
368                for item in &decl.items {
369                    if let TyTraitItem::Fn(f) = item {
370                        fns.push(*f.id());
371                    }
372                }
373            }
374        }
375
376        fns
377    }
378}
379
380#[derive(Clone, Debug, Serialize, Deserialize)]
381pub enum TyAstNodeContent {
382    Declaration(TyDecl),
383    Expression(TyExpression),
384    // a no-op node used for something that just issues a side effect, like an import statement.
385    SideEffect(TySideEffect),
386    Error(Box<[Span]>, #[serde(skip)] ErrorEmitted),
387}
388
389impl EqWithEngines for TyAstNodeContent {}
390impl PartialEqWithEngines for TyAstNodeContent {
391    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
392        match (self, other) {
393            (Self::Declaration(x), Self::Declaration(y)) => x.eq(y, ctx),
394            (Self::Expression(x), Self::Expression(y)) => x.eq(y, ctx),
395            (Self::SideEffect(_), Self::SideEffect(_)) => true,
396            _ => false,
397        }
398    }
399}
400
401impl HashWithEngines for TyAstNodeContent {
402    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
403        use TyAstNodeContent::*;
404        std::mem::discriminant(self).hash(state);
405        match self {
406            Declaration(decl) => {
407                decl.hash(state, engines);
408            }
409            Expression(exp) => {
410                exp.hash(state, engines);
411            }
412            SideEffect(effect) => {
413                effect.hash(state);
414            }
415            Error(_, _) => {}
416        }
417    }
418}
419
420impl TypeCheckAnalysis for TyAstNodeContent {
421    fn type_check_analyze(
422        &self,
423        handler: &Handler,
424        ctx: &mut TypeCheckAnalysisContext,
425    ) -> Result<(), ErrorEmitted> {
426        match self {
427            TyAstNodeContent::Declaration(node) => node.type_check_analyze(handler, ctx)?,
428            TyAstNodeContent::Expression(node) => node.type_check_analyze(handler, ctx)?,
429            TyAstNodeContent::SideEffect(_) => {}
430            TyAstNodeContent::Error(_, _) => {}
431        }
432        Ok(())
433    }
434}
435
436impl TypeCheckFinalization for TyAstNodeContent {
437    fn type_check_finalize(
438        &mut self,
439        handler: &Handler,
440        ctx: &mut TypeCheckFinalizationContext,
441    ) -> Result<(), ErrorEmitted> {
442        match self {
443            TyAstNodeContent::Declaration(node) => node.type_check_finalize(handler, ctx)?,
444            TyAstNodeContent::Expression(node) => node.type_check_finalize(handler, ctx)?,
445            TyAstNodeContent::SideEffect(_) => {}
446            TyAstNodeContent::Error(_, _) => {}
447        }
448        Ok(())
449    }
450}
451
452impl CollectTypesMetadata for TyAstNodeContent {
453    fn collect_types_metadata(
454        &self,
455        handler: &Handler,
456        ctx: &mut CollectTypesMetadataContext,
457    ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
458        use TyAstNodeContent::*;
459        match self {
460            Declaration(decl) => decl.collect_types_metadata(handler, ctx),
461            Expression(expr) => expr.collect_types_metadata(handler, ctx),
462            SideEffect(_) => Ok(vec![]),
463            Error(_, _) => Ok(vec![]),
464        }
465    }
466}
467
468impl GetDeclIdent for TyAstNodeContent {
469    fn get_decl_ident(&self, engines: &Engines) -> Option<Ident> {
470        match self {
471            TyAstNodeContent::Declaration(decl) => decl.get_decl_ident(engines),
472            TyAstNodeContent::Expression(_expr) => None, //expr.get_decl_ident(),
473            TyAstNodeContent::SideEffect(_) => None,
474            TyAstNodeContent::Error(_, _) => None,
475        }
476    }
477}