sway_core/semantic_analysis/namespace/
namespace.rs1use crate::{language::Visibility, Engines, Ident};
2
3use super::{module::Module, root::Root, ModulePath, ModulePathBuf};
4
5use sway_error::handler::{ErrorEmitted, Handler};
6use sway_types::{
7 constants::{CONTRACT_ID, PRELUDE, STD},
8 span::Span,
9};
10
11#[derive(Clone, Debug)]
13pub struct Namespace {
14 pub(crate) root: Root,
20 pub(crate) current_mod_path: ModulePathBuf,
26}
27
28impl Namespace {
29 pub fn new(
35 handler: &Handler,
36 engines: &Engines,
37 package_root: Root,
38 import_prelude_into_root: bool,
39 ) -> Result<Self, ErrorEmitted> {
40 let package_name = package_root.current_package_name().clone();
41 let mut res = Self {
42 root: package_root,
43 current_mod_path: vec![package_name],
44 };
45
46 if import_prelude_into_root {
47 res.import_implicits(handler, engines)?;
48 }
49 Ok(res)
50 }
51
52 pub fn root(self) -> Root {
53 self.root
54 }
55
56 pub fn root_ref(&self) -> &Root {
57 &self.root
58 }
59
60 pub fn current_module(&self) -> &Module {
61 self.root
62 .module_in_current_package(&self.current_mod_path)
63 .unwrap_or_else(|| panic!("Could not retrieve submodule for mod_path."))
64 }
65
66 pub fn current_module_mut(&mut self) -> &mut Module {
67 self.root
68 .module_mut_in_current_package(&self.current_mod_path)
69 .unwrap_or_else(|| panic!("Could not retrieve submodule for mod_path."))
70 }
71
72 pub(crate) fn current_module_has_submodule(&self, submod_name: &Ident) -> bool {
73 self.current_module()
74 .submodule(&[submod_name.clone()])
75 .is_some()
76 }
77
78 pub fn current_package_name(&self) -> &Ident {
79 self.root.current_package_name()
80 }
81
82 pub fn current_mod_path(&self) -> &ModulePathBuf {
84 &self.current_mod_path
85 }
86
87 pub fn prepend_module_path<'a>(
89 &'a self,
90 prefixes: impl IntoIterator<Item = &'a Ident>,
91 ) -> ModulePathBuf {
92 self.current_mod_path
93 .iter()
94 .chain(prefixes)
95 .cloned()
96 .collect()
97 }
98
99 pub fn parsed_path_to_full_path(
101 &self,
102 _engines: &Engines,
103 parsed_path: &ModulePathBuf,
104 is_relative_to_package_root: bool,
105 ) -> ModulePathBuf {
106 if is_relative_to_package_root {
107 let mut path = vec![self.current_package_name().clone()];
109 for ident in parsed_path.iter() {
110 path.push(ident.clone())
111 }
112 path
113 } else if self.current_module_has_submodule(&parsed_path[0]) {
114 self.prepend_module_path(parsed_path)
117 } else if self.module_is_external(parsed_path) {
118 parsed_path.to_vec()
120 } else {
121 self.prepend_module_path(parsed_path)
124 }
125 }
126
127 pub fn current_package_root_module(&self) -> &Module {
128 self.root.current_package_root_module()
129 }
130
131 pub fn module_from_absolute_path(&self, path: &ModulePathBuf) -> Option<&Module> {
132 self.root.module_from_absolute_path(path)
133 }
134
135 pub fn require_module_from_absolute_path(
137 &self,
138 handler: &Handler,
139 path: &ModulePathBuf,
140 ) -> Result<&Module, ErrorEmitted> {
141 self.root.require_module(handler, path)
142 }
143
144 pub(crate) fn module_is_submodule_of(
156 &self,
157 absolute_module_path: &ModulePath,
158 true_if_same: bool,
159 ) -> bool {
160 if self.current_mod_path.len() < absolute_module_path.len() {
161 return false;
162 }
163
164 let is_submodule = absolute_module_path
165 .iter()
166 .zip(self.current_mod_path.iter())
167 .all(|(left, right)| left == right);
168
169 if is_submodule {
170 if self.current_mod_path.len() == absolute_module_path.len() {
171 true_if_same
172 } else {
173 true
174 }
175 } else {
176 false
177 }
178 }
179
180 pub(crate) fn module_is_external(&self, absolute_module_path: &ModulePath) -> bool {
183 assert!(!absolute_module_path.is_empty(), "Absolute module path must have at least one element, because it always contains the package name.");
184
185 self.root.current_package_name() != &absolute_module_path[0]
186 }
187
188 pub fn package_exists(&self, name: &Ident) -> bool {
189 self.module_from_absolute_path(&vec![name.clone()])
190 .is_some()
191 }
192
193 pub(crate) fn module_has_binding(
194 &self,
195 engines: &Engines,
196 mod_path: &ModulePathBuf,
197 symbol: &Ident,
198 ) -> bool {
199 let dummy_handler = Handler::default();
200 if let Some(module) = self.module_from_absolute_path(mod_path) {
201 module
202 .resolve_symbol(&dummy_handler, engines, symbol)
203 .is_ok()
204 } else {
205 false
206 }
207 }
208
209 fn import_implicits(
211 &mut self,
212 handler: &Handler,
213 engines: &Engines,
214 ) -> Result<(), ErrorEmitted> {
215 let package_name = self.current_package_name().to_string();
217 let prelude_ident = Ident::new_no_span(PRELUDE.to_string());
218
219 if package_name == STD {
220 } else {
222 let std_string = STD.to_string();
224 if self.root.exists_as_external(&std_string) {
226 self.root.star_import(
227 handler,
228 engines,
229 &[Ident::new_no_span(std_string), prelude_ident],
230 &self.current_mod_path,
231 Visibility::Private,
232 )?
233 }
234 }
235
236 if self.root.is_contract_package() && self.current_mod_path.len() > 1 {
238 self.root.item_import(
240 handler,
241 engines,
242 &[Ident::new_no_span(package_name)],
243 &Ident::new_no_span(CONTRACT_ID.to_string()),
244 &self.current_mod_path,
245 None,
246 Visibility::Private,
247 )?
248 }
249
250 Ok(())
251 }
252
253 pub(crate) fn enter_submodule(
254 &mut self,
255 handler: &Handler,
256 engines: &Engines,
257 mod_name: Ident,
258 visibility: Visibility,
259 module_span: Span,
260 ) -> Result<(), ErrorEmitted> {
261 let mut import_implicits = false;
262
263 if !self
265 .current_module()
266 .submodules()
267 .contains_key(&mod_name.to_string())
268 {
269 self.current_module_mut()
271 .add_new_submodule(&mod_name, visibility, Some(module_span));
272 import_implicits = true;
273 }
274
275 self.current_mod_path.push(mod_name.clone());
277
278 if import_implicits {
280 self.import_implicits(handler, engines)?;
281 }
282
283 Ok(())
284 }
285
286 pub fn push_submodule(
288 &mut self,
289 handler: &Handler,
290 engines: &Engines,
291 mod_name: Ident,
292 visibility: Visibility,
293 module_span: Span,
294 ) -> Result<(), ErrorEmitted> {
295 match self.enter_submodule(handler, engines, mod_name, visibility, module_span) {
296 Ok(_) => Ok(()),
297 Err(e) => Err(e),
298 }
299 }
300
301 pub fn pop_submodule(&mut self) {
303 self.current_mod_path.pop();
304 }
305
306 pub(crate) fn star_import_to_current_module(
307 &mut self,
308 handler: &Handler,
309 engines: &Engines,
310 src: &ModulePath,
311 visibility: Visibility,
312 ) -> Result<(), ErrorEmitted> {
313 self.root
314 .star_import(handler, engines, src, &self.current_mod_path, visibility)
315 }
316
317 pub(crate) fn variant_star_import_to_current_module(
318 &mut self,
319 handler: &Handler,
320 engines: &Engines,
321 src: &ModulePath,
322 enum_name: &Ident,
323 visibility: Visibility,
324 ) -> Result<(), ErrorEmitted> {
325 self.root.variant_star_import(
326 handler,
327 engines,
328 src,
329 &self.current_mod_path,
330 enum_name,
331 visibility,
332 )
333 }
334
335 pub(crate) fn self_import_to_current_module(
336 &mut self,
337 handler: &Handler,
338 engines: &Engines,
339 src: &ModulePath,
340 alias: Option<Ident>,
341 visibility: Visibility,
342 ) -> Result<(), ErrorEmitted> {
343 self.root.self_import(
344 handler,
345 engines,
346 src,
347 &self.current_mod_path,
348 alias,
349 visibility,
350 )
351 }
352
353 pub(crate) fn item_import_to_current_module(
354 &mut self,
355 handler: &Handler,
356 engines: &Engines,
357 src: &ModulePath,
358 item: &Ident,
359 alias: Option<Ident>,
360 visibility: Visibility,
361 ) -> Result<(), ErrorEmitted> {
362 self.root.item_import(
363 handler,
364 engines,
365 src,
366 item,
367 &self.current_mod_path,
368 alias,
369 visibility,
370 )
371 }
372
373 #[allow(clippy::too_many_arguments)]
374 pub(crate) fn variant_import_to_current_module(
375 &mut self,
376 handler: &Handler,
377 engines: &Engines,
378 src: &ModulePath,
379 enum_name: &Ident,
380 variant_name: &Ident,
381 alias: Option<Ident>,
382 visibility: Visibility,
383 ) -> Result<(), ErrorEmitted> {
384 self.root.variant_import(
385 handler,
386 engines,
387 src,
388 enum_name,
389 variant_name,
390 &self.current_mod_path,
391 alias,
392 visibility,
393 )
394 }
395}