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