sway_core/semantic_analysis/namespace/
module.rs

1use crate::{
2    engine_threading::Engines,
3    language::{
4        ty::{self},
5        Visibility,
6    },
7    Ident, TypeId,
8};
9
10use super::{
11    lexical_scope::{Items, LexicalScope, ResolvedFunctionDecl},
12    LexicalScopeId, ModuleName, ModulePath, ModulePathBuf, ResolvedDeclaration,
13    ResolvedTraitImplItem, TraitMap,
14};
15
16use rustc_hash::FxHasher;
17use std::{collections::HashMap, hash::BuildHasherDefault};
18use sway_error::handler::Handler;
19use sway_error::{error::CompileError, handler::ErrorEmitted};
20use sway_types::{span::Span, Spanned};
21
22/// A single `Module` within a Sway project.
23///
24/// A `Module` is most commonly associated with an individual file of Sway code, e.g. a top-level
25/// script/predicate/contract file or some library dependency whether introduced via `mod` or the
26/// `[dependencies]` table of a `forc` manifest.
27///
28/// A `Module` contains a set of all items that exist within the lexical scope via declaration or
29/// importing, along with a map of each of its submodules.
30#[derive(Clone, Debug)]
31pub struct Module {
32    /// Submodules of the current module represented as an ordered map from each submodule's name
33    /// to the associated `Module`.
34    ///
35    /// Submodules are normally introduced in Sway code with the `mod foo;` syntax where `foo` is
36    /// some library dependency that we include as a submodule.
37    ///
38    /// Note that we *require* this map to produce deterministic codegen results which is why [`FxHasher`] is used.
39    submodules: im::HashMap<ModuleName, Module, BuildHasherDefault<FxHasher>>,
40    /// Keeps all lexical scopes associated with this module.
41    pub lexical_scopes: Vec<LexicalScope>,
42    /// Current lexical scope id in the lexical scope hierarchy stack.
43    pub current_lexical_scope_id: LexicalScopeId,
44    /// Maps between a span and the corresponding lexical scope id.
45    pub lexical_scopes_spans: HashMap<Span, LexicalScopeId>,
46    /// Name of the module, package name for root module, module name for other modules.
47    /// Module name used is the same as declared in `mod name;`.
48    name: Ident,
49    /// Whether or not this is a `pub` module
50    visibility: Visibility,
51    /// Empty span at the beginning of the file implementing the module
52    span: Option<Span>,
53    /// An absolute path from the `root` that represents the module location.
54    ///
55    /// The path of the root module in a package is `[package_name]`. If a module `X` is a submodule
56    /// of module `Y` which is a submodule of the root module in the package `P`, then the path is
57    /// `[P, Y, X]`.
58    mod_path: ModulePathBuf,
59}
60
61impl Module {
62    pub(super) fn new(
63        name: Ident,
64        visibility: Visibility,
65        span: Option<Span>,
66        parent_mod_path: &ModulePathBuf,
67    ) -> Self {
68        let mut mod_path = parent_mod_path.clone();
69        mod_path.push(name.clone());
70        Self {
71            visibility,
72            submodules: Default::default(),
73            lexical_scopes: vec![LexicalScope::default()],
74            lexical_scopes_spans: Default::default(),
75            current_lexical_scope_id: 0,
76            name,
77            span,
78            mod_path,
79        }
80    }
81
82    pub fn name(&self) -> &Ident {
83        &self.name
84    }
85
86    pub fn visibility(&self) -> &Visibility {
87        &self.visibility
88    }
89
90    pub fn span(&self) -> &Option<Span> {
91        &self.span
92    }
93
94    pub fn set_span(&mut self, span: Span) {
95        self.span = Some(span);
96    }
97
98    pub(super) fn add_new_submodule(
99        &mut self,
100        name: &Ident,
101        visibility: Visibility,
102        span: Option<Span>,
103    ) {
104        let module = Self::new(name.clone(), visibility, span, &self.mod_path);
105        self.submodules.insert(name.to_string(), module);
106    }
107
108    pub fn read<R>(&self, _engines: &crate::Engines, mut f: impl FnMut(&Module) -> R) -> R {
109        f(self)
110    }
111
112    pub fn write<R>(
113        &mut self,
114        _engines: &crate::Engines,
115        mut f: impl FnMut(&mut Module) -> R,
116    ) -> R {
117        f(self)
118    }
119
120    pub fn mod_path(&self) -> &ModulePath {
121        self.mod_path.as_slice()
122    }
123
124    pub fn mod_path_buf(&self) -> ModulePathBuf {
125        self.mod_path.clone()
126    }
127
128    /// Immutable access to this module's submodules.
129    pub fn submodules(&self) -> &im::HashMap<ModuleName, Module, BuildHasherDefault<FxHasher>> {
130        &self.submodules
131    }
132
133    pub fn has_submodule(&self, name: &Ident) -> bool {
134        self.submodule(&[name.clone()]).is_some()
135    }
136
137    /// Mutable access to this module's submodules.
138    pub fn submodules_mut(
139        &mut self,
140    ) -> &mut im::HashMap<ModuleName, Module, BuildHasherDefault<FxHasher>> {
141        &mut self.submodules
142    }
143
144    /// Lookup the submodule at the given path.
145    pub fn submodule(&self, path: &ModulePath) -> Option<&Module> {
146        let mut module = self;
147        for ident in path.iter() {
148            match module.submodules.get(ident.as_str()) {
149                Some(ns) => module = ns,
150                None => return None,
151            }
152        }
153        Some(module)
154    }
155
156    /// Unique access to the submodule at the given path.
157    pub fn submodule_mut(&mut self, path: &ModulePath) -> Option<&mut Module> {
158        let mut module = self;
159        for ident in path.iter() {
160            match module.submodules.get_mut(ident.as_str()) {
161                Some(ns) => module = ns,
162                None => return None,
163            }
164        }
165        Some(module)
166    }
167
168    /// Lookup the submodule at the given path.
169    ///
170    /// This should be used rather than `Index` when we don't yet know whether the module exists.
171    pub(crate) fn lookup_submodule(
172        &self,
173        handler: &Handler,
174        path: &[Ident],
175    ) -> Result<&Module, ErrorEmitted> {
176        match self.submodule(path) {
177            None => Err(handler.emit_err(module_not_found(path, true))),
178            Some(module) => Ok(module),
179        }
180    }
181
182    /// Returns the root lexical scope id associated with this module.
183    pub fn root_lexical_scope_id(&self) -> LexicalScopeId {
184        0
185    }
186
187    /// Returns the root lexical scope associated with this module.
188    pub fn root_lexical_scope(&self) -> &LexicalScope {
189        self.lexical_scopes
190            .get(self.root_lexical_scope_id())
191            .unwrap()
192    }
193
194    pub fn get_lexical_scope(&self, id: LexicalScopeId) -> Option<&LexicalScope> {
195        self.lexical_scopes.get(id)
196    }
197
198    pub fn get_lexical_scope_mut(&mut self, id: LexicalScopeId) -> Option<&mut LexicalScope> {
199        self.lexical_scopes.get_mut(id)
200    }
201
202    /// Returns the current lexical scope associated with this module.
203    pub fn current_lexical_scope(&self) -> &LexicalScope {
204        self.lexical_scopes
205            .get(self.current_lexical_scope_id)
206            .unwrap()
207    }
208
209    /// Returns the mutable current lexical scope associated with this module.
210    pub fn current_lexical_scope_mut(&mut self) -> &mut LexicalScope {
211        self.lexical_scopes
212            .get_mut(self.current_lexical_scope_id)
213            .unwrap()
214    }
215
216    /// The collection of items declared by this module's current lexical scope.
217    pub fn current_items(&self) -> &Items {
218        &self.current_lexical_scope().items
219    }
220
221    /// The collection of items declared by this module's root lexical scope.
222    pub fn root_items(&self) -> &Items {
223        &self.root_lexical_scope().items
224    }
225
226    /// The mutable collection of items declared by this module's current lexical scope.
227    pub fn current_items_mut(&mut self) -> &mut Items {
228        &mut self.current_lexical_scope_mut().items
229    }
230
231    pub fn current_lexical_scope_id(&self) -> LexicalScopeId {
232        self.current_lexical_scope_id
233    }
234
235    /// Enters the scope with the given span in the module's lexical scope hierarchy.
236    pub fn enter_lexical_scope(
237        &mut self,
238        handler: &Handler,
239        span: Span,
240    ) -> Result<LexicalScopeId, ErrorEmitted> {
241        let id_opt = self.lexical_scopes_spans.get(&span);
242        match id_opt {
243            Some(id) => {
244                let visitor_parent = self.current_lexical_scope_id;
245                self.current_lexical_scope_id = *id;
246                self.current_lexical_scope_mut().visitor_parent = Some(visitor_parent);
247
248                Ok(self.current_lexical_scope_id)
249            }
250            None => Err(handler.emit_err(CompileError::Internal(
251                "Could not find a valid lexical scope for this source location.",
252                span.clone(),
253            ))),
254        }
255    }
256
257    /// Pushes a new scope to the module's lexical scope hierarchy.
258    pub fn push_new_lexical_scope(
259        &mut self,
260        span: Span,
261        declaration: Option<ResolvedDeclaration>,
262    ) -> LexicalScopeId {
263        let previous_scope_id = self.current_lexical_scope_id();
264        let previous_scope = self.lexical_scopes.get(previous_scope_id).unwrap();
265        let new_scoped_id = {
266            self.lexical_scopes.push(LexicalScope {
267                parent: Some(previous_scope_id),
268                visitor_parent: Some(previous_scope_id),
269                items: Items {
270                    symbols_unique_while_collecting_unifications: previous_scope
271                        .items
272                        .symbols_unique_while_collecting_unifications
273                        .clone(),
274                    ..Default::default()
275                },
276                declaration,
277                ..Default::default()
278            });
279            self.lexical_scopes.len() - 1
280        };
281        let previous_scope = self.lexical_scopes.get_mut(previous_scope_id).unwrap();
282        previous_scope.children.push(new_scoped_id);
283        self.current_lexical_scope_id = new_scoped_id;
284        self.lexical_scopes_spans.insert(span, new_scoped_id);
285        new_scoped_id
286    }
287
288    /// Pops the current scope from the module's lexical scope hierarchy.
289    pub fn pop_lexical_scope(&mut self) {
290        let parent_scope_id = self.current_lexical_scope().visitor_parent;
291        self.current_lexical_scope_id = parent_scope_id.unwrap(); // panics if pops do not match pushes
292    }
293
294    pub fn walk_scope_chain_early_return<T>(
295        &self,
296        mut f: impl FnMut(&LexicalScope) -> Result<Option<T>, ErrorEmitted>,
297    ) -> Result<Option<T>, ErrorEmitted> {
298        let mut lexical_scope_opt = Some(self.current_lexical_scope());
299        while let Some(lexical_scope) = lexical_scope_opt {
300            let result = f(lexical_scope)?;
301            if let Some(result) = result {
302                return Ok(Some(result));
303            }
304            if let Some(parent_scope_id) = lexical_scope.parent {
305                lexical_scope_opt = self.get_lexical_scope(parent_scope_id);
306            } else {
307                lexical_scope_opt = None;
308            }
309        }
310        Ok(None)
311    }
312
313    pub fn walk_scope_chain(&self, mut f: impl FnMut(&LexicalScope)) {
314        let mut lexical_scope_opt = Some(self.current_lexical_scope());
315        while let Some(lexical_scope) = lexical_scope_opt {
316            f(lexical_scope);
317            if let Some(parent_scope_id) = lexical_scope.parent {
318                lexical_scope_opt = self.get_lexical_scope(parent_scope_id);
319            } else {
320                lexical_scope_opt = None;
321            }
322        }
323    }
324
325    pub fn get_items_for_type(
326        &self,
327        engines: &Engines,
328        type_id: TypeId,
329    ) -> Vec<ResolvedTraitImplItem> {
330        TraitMap::get_items_for_type(self, engines, type_id)
331    }
332
333    pub fn resolve_symbol(
334        &self,
335        handler: &Handler,
336        engines: &Engines,
337        symbol: &Ident,
338    ) -> Result<(ResolvedDeclaration, ModulePathBuf), ErrorEmitted> {
339        let mut last_handler = Handler::default();
340        let ret = self.walk_scope_chain_early_return(|lexical_scope| {
341            last_handler = Handler::default();
342            Ok(lexical_scope
343                .items
344                .resolve_symbol(&last_handler, engines, symbol, &self.mod_path)
345                .ok()
346                .flatten())
347        })?;
348
349        handler.append(last_handler);
350
351        if let Some(ret) = ret {
352            Ok(ret)
353        } else {
354            // Symbol not found
355            Err(handler.emit_err(CompileError::SymbolNotFound {
356                name: symbol.clone(),
357                span: symbol.span(),
358            }))
359        }
360    }
361
362    pub fn get_methods_for_type(
363        &self,
364        engines: &Engines,
365        type_id: TypeId,
366    ) -> Vec<ResolvedFunctionDecl> {
367        self.get_items_for_type(engines, type_id)
368            .into_iter()
369            .filter_map(|item| match item {
370                ResolvedTraitImplItem::Parsed(_) => unreachable!(),
371                ResolvedTraitImplItem::Typed(item) => match item {
372                    ty::TyTraitItem::Fn(decl_ref) => Some(ResolvedFunctionDecl::Typed(decl_ref)),
373                    ty::TyTraitItem::Constant(_decl_ref) => None,
374                    ty::TyTraitItem::Type(_decl_ref) => None,
375                },
376            })
377            .collect::<Vec<_>>()
378    }
379}
380
381/// Create a ModuleNotFound error.
382/// If skip_package_name is true, then the package name is not emitted as part of the error
383/// message. This is used when the module was supposed to be found in the current package rather
384/// than in an external one.
385pub fn module_not_found(path: &[Ident], skip_package_name: bool) -> CompileError {
386    CompileError::ModuleNotFound {
387        span: path
388            .iter()
389            .skip(if skip_package_name { 1 } else { 0 })
390            .fold(path.last().unwrap().span(), |acc, this_one| {
391                if acc.source_id() == this_one.span().source_id() {
392                    Span::join(acc, &this_one.span())
393                } else {
394                    acc
395                }
396            }),
397        name: path
398            .iter()
399            .skip(if skip_package_name { 1 } else { 0 })
400            .map(|x| x.as_str())
401            .collect::<Vec<_>>()
402            .join("::"),
403    }
404}