sway_core/semantic_analysis/
program.rs1use std::sync::Arc;
2
3use crate::{
4 language::{
5 parsed::ParseProgram,
6 ty::{self, TyModule, TyProgram},
7 },
8 metadata::MetadataManager,
9 semantic_analysis::{
10 namespace::{self, Package},
11 TypeCheckContext,
12 },
13 BuildConfig, Engines,
14};
15use sway_error::handler::{ErrorEmitted, Handler};
16use sway_features::ExperimentalFeatures;
17use sway_ir::{Context, Module};
18
19use super::{
20 symbol_collection_context::SymbolCollectionContext, TypeCheckAnalysis,
21 TypeCheckAnalysisContext, TypeCheckFinalization, TypeCheckFinalizationContext,
22};
23
24#[derive(Clone, Debug)]
25pub struct TypeCheckFailed {
26 pub root_module: Option<Arc<TyModule>>,
27 pub namespace: Package,
28 pub error: ErrorEmitted,
29}
30
31impl TyProgram {
32 pub fn collect(
37 handler: &Handler,
38 engines: &Engines,
39 parsed: &ParseProgram,
40 namespace: namespace::Namespace,
41 ) -> Result<SymbolCollectionContext, ErrorEmitted> {
42 let mut ctx = SymbolCollectionContext::new(namespace);
43 let ParseProgram { root, kind: _ } = parsed;
44
45 ty::TyModule::collect(handler, engines, &mut ctx, root)?;
46 Ok(ctx)
47 }
48
49 #[allow(clippy::too_many_arguments)]
54 pub fn type_check(
55 handler: &Handler,
56 engines: &Engines,
57 parsed: &ParseProgram,
58 collection_ctx: &mut SymbolCollectionContext,
59 mut namespace: namespace::Namespace,
60 package_name: &str,
61 build_config: Option<&BuildConfig>,
62 experimental: ExperimentalFeatures,
63 ) -> Result<Self, TypeCheckFailed> {
64 let mut ctx =
65 TypeCheckContext::from_root(&mut namespace, collection_ctx, engines, experimental)
66 .with_kind(parsed.kind);
67
68 let ParseProgram { root, kind } = parsed;
69
70 let root = ty::TyModule::type_check(
71 handler,
72 ctx.by_ref(),
73 engines,
74 parsed.kind,
75 root,
76 build_config,
77 )
78 .map_err(|error| TypeCheckFailed {
79 error,
80 root_module: None,
81 namespace: ctx.namespace.current_package_ref().clone(),
82 })?;
83
84 let experimental = ctx.experimental;
85 let (kind, declarations, configurables) =
86 Self::validate_root(handler, engines, &root, *kind, package_name, experimental)
87 .map_err(|error| TypeCheckFailed {
88 error,
89 root_module: Some(root.clone()),
90 namespace: ctx.namespace.current_package_ref().clone(),
91 })?;
92
93 let mut namespace = ctx.namespace().clone();
94 let skip_coherence_checks = build_config
97 .is_some_and(|config| config.lsp_mode.as_ref().is_some_and(|_lsp_mode| true));
98 if !skip_coherence_checks {
99 Self::validate_coherence(handler, engines, &root, &mut namespace).map_err(|error| {
100 TypeCheckFailed {
101 error,
102 root_module: Some(root.clone()),
103 namespace: ctx.namespace.current_package_ref().clone(),
104 }
105 })?;
106 }
107
108 let program = TyProgram {
109 kind,
110 root_module: (*root).clone(),
111 namespace,
112 declarations,
113 configurables,
114 storage_slots: vec![],
115 logged_types: vec![],
116 messages_types: vec![],
117 };
118
119 Ok(program)
120 }
121
122 pub(crate) fn get_typed_program_with_initialized_storage_slots(
123 &mut self,
124 handler: &Handler,
125 engines: &Engines,
126 context: &mut Context,
127 md_mgr: &mut MetadataManager,
128 module: Module,
129 ) -> Result<(), ErrorEmitted> {
130 let decl_engine = engines.de();
131 match &self.kind {
132 ty::TyProgramKind::Contract { .. } => {
133 let storage_decl = self
134 .declarations
135 .iter()
136 .find(|decl| matches!(decl, ty::TyDecl::StorageDecl { .. }));
137
138 match storage_decl {
140 Some(ty::TyDecl::StorageDecl(ty::StorageDecl { decl_id, .. })) => {
141 let decl = decl_engine.get_storage(decl_id);
142 let mut storage_slots = decl.get_initialized_storage_slots(
143 handler, engines, context, md_mgr, module,
144 )?;
145 storage_slots.sort();
148 self.storage_slots = storage_slots;
149 Ok(())
150 }
151 _ => {
152 self.storage_slots = vec![];
153 Ok(())
154 }
155 }
156 }
157 _ => {
158 self.storage_slots = vec![];
159 Ok(())
160 }
161 }
162 }
163}
164
165impl TypeCheckAnalysis for TyProgram {
166 fn type_check_analyze(
167 &self,
168 handler: &Handler,
169 ctx: &mut TypeCheckAnalysisContext,
170 ) -> Result<(), ErrorEmitted> {
171 for node in self.root_module.all_nodes.iter() {
172 node.type_check_analyze(handler, ctx)?;
173 }
174 Ok(())
175 }
176}
177
178impl TypeCheckFinalization for TyProgram {
179 fn type_check_finalize(
180 &mut self,
181 handler: &Handler,
182 ctx: &mut TypeCheckFinalizationContext,
183 ) -> Result<(), ErrorEmitted> {
184 handler.scope(|handler| {
185 for node in self.root_module.all_nodes.iter_mut() {
186 let _ = node.type_check_finalize(handler, ctx);
187 }
188 Ok(())
189 })
190 }
191}