Skip to main content

sway_core/language/ty/
ast_node.rs

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