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