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 &mut self.content {
151            TyAstNodeContent::Declaration(TyDecl::VariableDecl(decl)) => decl
152                .body
153                .materialize_const_generics(engines, handler, name, value),
154            TyAstNodeContent::Expression(expr) => {
155                expr.materialize_const_generics(engines, handler, name, value)
156            }
157            _ => Ok(()),
158        }
159    }
160}
161
162impl TyAstNode {
163    /// Returns `true` if this AST node will be exported in a library, i.e. it is a public declaration.
164    pub(crate) fn is_public(&self, decl_engine: &DeclEngine) -> bool {
165        match &self.content {
166            TyAstNodeContent::Declaration(decl) => decl.visibility(decl_engine).is_public(),
167            TyAstNodeContent::Expression(_)
168            | TyAstNodeContent::SideEffect(_)
169            | TyAstNodeContent::Error(_, _) => false,
170        }
171    }
172
173    /// Check to see if this node is a function declaration with generic type parameters.
174    pub(crate) fn is_generic_function(&self, decl_engine: &DeclEngine) -> bool {
175        match &self {
176            TyAstNode {
177                span: _,
178                content:
179                    TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl {
180                        decl_id, ..
181                    })),
182                ..
183            } => {
184                let fn_decl = decl_engine.get_function(decl_id);
185                let TyFunctionDecl {
186                    type_parameters, ..
187                } = &*fn_decl;
188                !type_parameters.is_empty()
189            }
190            _ => false,
191        }
192    }
193
194    /// Check to see if this node is a function declaration of a function annotated as test.
195    pub(crate) fn is_test_function(&self, decl_engine: &DeclEngine) -> bool {
196        match &self {
197            TyAstNode {
198                span: _,
199                content:
200                    TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl {
201                        decl_id, ..
202                    })),
203                ..
204            } => {
205                let fn_decl = decl_engine.get_function(decl_id);
206                let TyFunctionDecl { attributes, .. } = &*fn_decl;
207                attributes.has_any_of_kind(AttributeKind::Test)
208            }
209            _ => false,
210        }
211    }
212
213    pub(crate) fn type_info(&self, type_engine: &TypeEngine) -> TypeInfo {
214        // return statement should be ()
215        match &self.content {
216            TyAstNodeContent::Declaration(_) => TypeInfo::Tuple(Vec::new()),
217            TyAstNodeContent::Expression(TyExpression { return_type, .. }) => {
218                (*type_engine.get(*return_type)).clone()
219            }
220            TyAstNodeContent::SideEffect(_) => TypeInfo::Tuple(Vec::new()),
221            TyAstNodeContent::Error(_, error) => TypeInfo::ErrorRecovery(*error),
222        }
223    }
224
225    pub(crate) fn check_deprecated(
226        &self,
227        engines: &Engines,
228        handler: &Handler,
229        allow_deprecated: &mut AllowDeprecatedState,
230    ) {
231        match &self.content {
232            TyAstNodeContent::Declaration(node) => match node {
233                TyDecl::VariableDecl(decl) => {
234                    decl.body
235                        .check_deprecated(engines, handler, allow_deprecated);
236                }
237                TyDecl::ConstantDecl(decl) => {
238                    let decl = engines.de().get(&decl.decl_id);
239                    if let Some(value) = &decl.value {
240                        value.check_deprecated(engines, handler, allow_deprecated);
241                    }
242                }
243                TyDecl::ConfigurableDecl(decl) => {
244                    let decl = engines.de().get(&decl.decl_id);
245                    if let Some(value) = &decl.value {
246                        value.check_deprecated(engines, handler, allow_deprecated);
247                    }
248                }
249                TyDecl::ConstGenericDecl(_) => {
250                    todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
251                }
252                TyDecl::TraitTypeDecl(_) => {}
253                TyDecl::FunctionDecl(decl) => {
254                    let decl = engines.de().get(&decl.decl_id);
255                    let token = allow_deprecated.enter(decl.attributes.clone());
256                    for node in decl.body.contents.iter() {
257                        node.check_deprecated(engines, handler, allow_deprecated);
258                    }
259                    allow_deprecated.exit(token);
260                }
261                TyDecl::ImplSelfOrTrait(decl) => {
262                    let decl = engines.de().get(&decl.decl_id);
263                    for item in decl.items.iter() {
264                        match item {
265                            TyTraitItem::Fn(item) => {
266                                let decl = engines.de().get(item.id());
267                                let token = allow_deprecated.enter(decl.attributes.clone());
268                                for node in decl.body.contents.iter() {
269                                    node.check_deprecated(engines, handler, allow_deprecated);
270                                }
271                                allow_deprecated.exit(token);
272                            }
273                            TyTraitItem::Constant(item) => {
274                                let decl = engines.de().get(item.id());
275                                if let Some(expr) = decl.value.as_ref() {
276                                    expr.check_deprecated(engines, handler, allow_deprecated);
277                                }
278                            }
279                            TyTraitItem::Type(_) => {}
280                        }
281                    }
282                }
283                TyDecl::AbiDecl(_)
284                | TyDecl::GenericTypeForFunctionScope(_)
285                | TyDecl::ErrorRecovery(_, _)
286                | TyDecl::StorageDecl(_)
287                | TyDecl::TraitDecl(_)
288                | TyDecl::StructDecl(_)
289                | TyDecl::EnumDecl(_)
290                | TyDecl::EnumVariantDecl(_)
291                | TyDecl::TypeAliasDecl(_) => {}
292            },
293            TyAstNodeContent::Expression(node) => {
294                node.check_deprecated(engines, handler, allow_deprecated);
295            }
296            TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {}
297        }
298    }
299
300    pub(crate) fn check_recursive(
301        &self,
302        engines: &Engines,
303        handler: &Handler,
304    ) -> Result<(), ErrorEmitted> {
305        handler.scope(|handler| {
306            match &self.content {
307                TyAstNodeContent::Declaration(node) => match node {
308                    TyDecl::VariableDecl(_decl) => {}
309                    TyDecl::ConstantDecl(_decl) => {}
310                    TyDecl::ConfigurableDecl(_decl) => {}
311                    TyDecl::ConstGenericDecl(_decl) => {
312                        todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
313                    }
314                    TyDecl::TraitTypeDecl(_) => {}
315                    TyDecl::FunctionDecl(decl) => {
316                        let fn_decl_id = decl.decl_id;
317                        let mut ctx = TypeCheckAnalysisContext::new(engines);
318                        let _ = fn_decl_id.type_check_analyze(handler, &mut ctx);
319                        let _ = ctx.check_recursive_calls(handler);
320                    }
321                    TyDecl::ImplSelfOrTrait(decl) => {
322                        let decl = engines.de().get(&decl.decl_id);
323                        for item in decl.items.iter() {
324                            let mut ctx = TypeCheckAnalysisContext::new(engines);
325                            let _ = item.type_check_analyze(handler, &mut ctx);
326                            let _ = ctx.check_recursive_calls(handler);
327                        }
328                    }
329                    TyDecl::AbiDecl(_)
330                    | TyDecl::GenericTypeForFunctionScope(_)
331                    | TyDecl::ErrorRecovery(_, _)
332                    | TyDecl::StorageDecl(_)
333                    | TyDecl::TraitDecl(_)
334                    | TyDecl::StructDecl(_)
335                    | TyDecl::EnumDecl(_)
336                    | TyDecl::EnumVariantDecl(_)
337                    | TyDecl::TypeAliasDecl(_) => {}
338                },
339                TyAstNodeContent::Expression(_node) => {}
340                TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {}
341            };
342            Ok(())
343        })
344    }
345
346    pub fn contract_supertrait_fns(&self, engines: &Engines) -> Vec<DeclId<TyFunctionDecl>> {
347        let mut fns = vec![];
348
349        if let TyAstNodeContent::Declaration(TyDecl::ImplSelfOrTrait(decl)) = &self.content {
350            let decl = engines.de().get(&decl.decl_id);
351            if decl.is_impl_contract(engines.te()) {
352                for item in &decl.supertrait_items {
353                    if let TyTraitItem::Fn(f) = item {
354                        fns.push(*f.id());
355                    }
356                }
357            }
358        }
359
360        fns
361    }
362
363    pub fn contract_fns(&self, engines: &Engines) -> Vec<DeclId<TyFunctionDecl>> {
364        let mut fns = vec![];
365
366        if let TyAstNodeContent::Declaration(TyDecl::ImplSelfOrTrait(decl)) = &self.content {
367            let decl = engines.de().get(&decl.decl_id);
368            if decl.is_impl_contract(engines.te()) {
369                for item in &decl.items {
370                    if let TyTraitItem::Fn(f) = item {
371                        fns.push(*f.id());
372                    }
373                }
374            }
375        }
376
377        fns
378    }
379}
380
381#[derive(Clone, Debug, Serialize, Deserialize)]
382pub enum TyAstNodeContent {
383    Declaration(TyDecl),
384    Expression(TyExpression),
385    // a no-op node used for something that just issues a side effect, like an import statement.
386    SideEffect(TySideEffect),
387    Error(Box<[Span]>, #[serde(skip)] ErrorEmitted),
388}
389
390impl EqWithEngines for TyAstNodeContent {}
391impl PartialEqWithEngines for TyAstNodeContent {
392    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
393        match (self, other) {
394            (Self::Declaration(x), Self::Declaration(y)) => x.eq(y, ctx),
395            (Self::Expression(x), Self::Expression(y)) => x.eq(y, ctx),
396            (Self::SideEffect(_), Self::SideEffect(_)) => true,
397            _ => false,
398        }
399    }
400}
401
402impl HashWithEngines for TyAstNodeContent {
403    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
404        use TyAstNodeContent::*;
405        std::mem::discriminant(self).hash(state);
406        match self {
407            Declaration(decl) => {
408                decl.hash(state, engines);
409            }
410            Expression(exp) => {
411                exp.hash(state, engines);
412            }
413            SideEffect(effect) => {
414                effect.hash(state);
415            }
416            Error(_, _) => {}
417        }
418    }
419}
420
421impl TypeCheckAnalysis for TyAstNodeContent {
422    fn type_check_analyze(
423        &self,
424        handler: &Handler,
425        ctx: &mut TypeCheckAnalysisContext,
426    ) -> Result<(), ErrorEmitted> {
427        match self {
428            TyAstNodeContent::Declaration(node) => node.type_check_analyze(handler, ctx)?,
429            TyAstNodeContent::Expression(node) => node.type_check_analyze(handler, ctx)?,
430            TyAstNodeContent::SideEffect(_) => {}
431            TyAstNodeContent::Error(_, _) => {}
432        }
433        Ok(())
434    }
435}
436
437impl TypeCheckFinalization for TyAstNodeContent {
438    fn type_check_finalize(
439        &mut self,
440        handler: &Handler,
441        ctx: &mut TypeCheckFinalizationContext,
442    ) -> Result<(), ErrorEmitted> {
443        match self {
444            TyAstNodeContent::Declaration(node) => node.type_check_finalize(handler, ctx)?,
445            TyAstNodeContent::Expression(node) => node.type_check_finalize(handler, ctx)?,
446            TyAstNodeContent::SideEffect(_) => {}
447            TyAstNodeContent::Error(_, _) => {}
448        }
449        Ok(())
450    }
451}
452
453impl CollectTypesMetadata for TyAstNodeContent {
454    fn collect_types_metadata(
455        &self,
456        handler: &Handler,
457        ctx: &mut CollectTypesMetadataContext,
458    ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
459        use TyAstNodeContent::*;
460        match self {
461            Declaration(decl) => decl.collect_types_metadata(handler, ctx),
462            Expression(expr) => expr.collect_types_metadata(handler, ctx),
463            SideEffect(_) => Ok(vec![]),
464            Error(_, _) => Ok(vec![]),
465        }
466    }
467}
468
469impl GetDeclIdent for TyAstNodeContent {
470    fn get_decl_ident(&self, engines: &Engines) -> Option<Ident> {
471        match self {
472            TyAstNodeContent::Declaration(decl) => decl.get_decl_ident(engines),
473            TyAstNodeContent::Expression(_expr) => None, //expr.get_decl_ident(),
474            TyAstNodeContent::SideEffect(_) => None,
475            TyAstNodeContent::Error(_, _) => None,
476        }
477    }
478}