Skip to main content

sway_core/semantic_analysis/
program.rs

1use std::sync::Arc;
2
3use super::symbol_collection_context::SymbolCollectionContext;
4use crate::{
5    language::{
6        parsed::ParseProgram,
7        ty::{self, TyModule, TyProgram},
8    },
9    metadata::MetadataManager,
10    semantic_analysis::{
11        namespace::{self, Package},
12        TypeCheckContext,
13    },
14    BuildConfig, Engines,
15};
16use sway_error::handler::{ErrorEmitted, Handler};
17use sway_ir::{Context, Module};
18
19#[derive(Clone, Debug)]
20pub struct TypeCheckFailed {
21    pub root_module: Option<Arc<TyModule>>,
22    pub namespace: Package,
23    pub error: ErrorEmitted,
24}
25
26impl TyProgram {
27    /// Collects the given parsed program to produce a symbol maps.
28    ///
29    /// The given `initial_namespace` acts as an initial state for each module within this program.
30    /// It should contain a submodule for each library package dependency.
31    pub fn collect(
32        handler: &Handler,
33        engines: &Engines,
34        parsed: &ParseProgram,
35        namespace: namespace::Namespace,
36    ) -> Result<SymbolCollectionContext, ErrorEmitted> {
37        let mut ctx = SymbolCollectionContext::new(namespace);
38        let ParseProgram { root, kind: _ } = parsed;
39
40        ty::TyModule::collect(handler, engines, &mut ctx, root)?;
41        Ok(ctx)
42    }
43
44    /// Type-check the given parsed program to produce a typed program.
45    ///
46    /// The given `namespace` acts as an initial state for each module within this program.
47    /// It should contain a submodule for each library package dependency.
48    #[allow(clippy::result_large_err)]
49    #[allow(clippy::too_many_arguments)]
50    pub fn type_check(
51        handler: &Handler,
52        engines: &Engines,
53        parsed: &ParseProgram,
54        package_name: &str,
55        build_config: Option<&BuildConfig>,
56        ctx: &mut TypeCheckContext,
57    ) -> Result<Self, TypeCheckFailed> {
58        let ParseProgram { root, kind } = parsed;
59
60        let root = ty::TyModule::type_check(
61            handler,
62            ctx.by_ref(),
63            engines,
64            parsed.kind,
65            root,
66            build_config,
67        )
68        .map_err(|error| TypeCheckFailed {
69            error,
70            root_module: None,
71            namespace: ctx.namespace.current_package_ref().clone(),
72        })?;
73
74        let experimental = ctx.experimental;
75        let (kind, declarations, configurables) =
76            Self::validate_root(handler, engines, &root, *kind, package_name, experimental)
77                .map_err(|error| TypeCheckFailed {
78                    error,
79                    root_module: Some(root.clone()),
80                    namespace: ctx.namespace.current_package_ref().clone(),
81                })?;
82
83        let mut namespace = ctx.namespace().clone();
84        Self::validate_coherence(handler, engines, &root, &mut namespace).map_err(|error| {
85            TypeCheckFailed {
86                error,
87                root_module: Some(root.clone()),
88                namespace: ctx.namespace.current_package_ref().clone(),
89            }
90        })?;
91
92        let program = TyProgram {
93            kind,
94            root_module: (*root).clone(),
95            namespace,
96            declarations,
97            configurables,
98            storage_slots: vec![],
99            logged_types: vec![],
100            messages_types: vec![],
101        };
102
103        Ok(program)
104    }
105
106    pub(crate) fn get_typed_program_with_initialized_storage_slots(
107        &mut self,
108        handler: &Handler,
109        engines: &Engines,
110        context: &mut Context,
111        md_mgr: &mut MetadataManager,
112        module: Module,
113    ) -> Result<(), ErrorEmitted> {
114        let decl_engine = engines.de();
115        match &self.kind {
116            ty::TyProgramKind::Contract { .. } => {
117                let storage_decl = self
118                    .declarations
119                    .iter()
120                    .find(|decl| matches!(decl, ty::TyDecl::StorageDecl { .. }));
121
122                // Expecting at most a single storage declaration
123                match storage_decl {
124                    Some(ty::TyDecl::StorageDecl(ty::StorageDecl { decl_id, .. })) => {
125                        let decl = decl_engine.get_storage(decl_id);
126                        let mut storage_slots = decl.get_initialized_storage_slots(
127                            handler, engines, context, md_mgr, module,
128                        )?;
129                        // Sort the slots to standardize the output. Not strictly required by the
130                        // spec.
131                        storage_slots.sort();
132                        self.storage_slots = storage_slots;
133                        Ok(())
134                    }
135                    _ => {
136                        self.storage_slots = vec![];
137                        Ok(())
138                    }
139                }
140            }
141            _ => {
142                self.storage_slots = vec![];
143                Ok(())
144            }
145        }
146    }
147}