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