Skip to main content

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