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(crate) fn import_cached_submodule(&mut self, name: &Ident, module: Module) {
109        self.submodules.insert(name.to_string(), module);
110    }
111
112    pub fn read<R>(&self, _engines: &crate::Engines, mut f: impl FnMut(&Module) -> R) -> R {
113        f(self)
114    }
115
116    pub fn write<R>(
117        &mut self,
118        _engines: &crate::Engines,
119        mut f: impl FnMut(&mut Module) -> R,
120    ) -> R {
121        f(self)
122    }
123
124    pub fn mod_path(&self) -> &ModulePath {
125        self.mod_path.as_slice()
126    }
127
128    pub fn mod_path_buf(&self) -> ModulePathBuf {
129        self.mod_path.clone()
130    }
131
132    /// Immutable access to this module's submodules.
133    pub fn submodules(&self) -> &im::HashMap<ModuleName, Module, BuildHasherDefault<FxHasher>> {
134        &self.submodules
135    }
136
137    pub fn has_submodule(&self, name: &Ident) -> bool {
138        self.submodule(&[name.clone()]).is_some()
139    }
140
141    /// Mutable access to this module's submodules.
142    pub fn submodules_mut(
143        &mut self,
144    ) -> &mut im::HashMap<ModuleName, Module, BuildHasherDefault<FxHasher>> {
145        &mut self.submodules
146    }
147
148    /// Lookup the submodule at the given path.
149    pub fn submodule(&self, path: &ModulePath) -> Option<&Module> {
150        let mut module = self;
151        for ident in path.iter() {
152            match module.submodules.get(ident.as_str()) {
153                Some(ns) => module = ns,
154                None => return None,
155            }
156        }
157        Some(module)
158    }
159
160    /// Unique access to the submodule at the given path.
161    pub fn submodule_mut(&mut self, path: &ModulePath) -> Option<&mut Module> {
162        let mut module = self;
163        for ident in path.iter() {
164            match module.submodules.get_mut(ident.as_str()) {
165                Some(ns) => module = ns,
166                None => return None,
167            }
168        }
169        Some(module)
170    }
171
172    /// Lookup the submodule at the given path.
173    ///
174    /// This should be used rather than `Index` when we don't yet know whether the module exists.
175    pub(crate) fn lookup_submodule(
176        &self,
177        handler: &Handler,
178        path: &[Ident],
179    ) -> Result<&Module, ErrorEmitted> {
180        match self.submodule(path) {
181            None => Err(handler.emit_err(module_not_found(path, true))),
182            Some(module) => Ok(module),
183        }
184    }
185
186    /// Returns the root lexical scope id associated with this module.
187    pub fn root_lexical_scope_id(&self) -> LexicalScopeId {
188        0
189    }
190
191    /// Returns the root lexical scope associated with this module.
192    pub fn root_lexical_scope(&self) -> &LexicalScope {
193        self.lexical_scopes
194            .get(self.root_lexical_scope_id())
195            .unwrap()
196    }
197
198    pub fn get_lexical_scope(&self, id: LexicalScopeId) -> Option<&LexicalScope> {
199        self.lexical_scopes.get(id)
200    }
201
202    pub fn get_lexical_scope_mut(&mut self, id: LexicalScopeId) -> Option<&mut LexicalScope> {
203        self.lexical_scopes.get_mut(id)
204    }
205
206    /// Returns the current lexical scope associated with this module.
207    pub fn current_lexical_scope(&self) -> &LexicalScope {
208        self.lexical_scopes
209            .get(self.current_lexical_scope_id)
210            .unwrap()
211    }
212
213    /// Returns the mutable current lexical scope associated with this module.
214    pub fn current_lexical_scope_mut(&mut self) -> &mut LexicalScope {
215        self.lexical_scopes
216            .get_mut(self.current_lexical_scope_id)
217            .unwrap()
218    }
219
220    /// The collection of items declared by this module's current lexical scope.
221    pub fn current_items(&self) -> &Items {
222        &self.current_lexical_scope().items
223    }
224
225    /// The collection of items declared by this module's root lexical scope.
226    pub fn root_items(&self) -> &Items {
227        &self.root_lexical_scope().items
228    }
229
230    /// The mutable collection of items declared by this module's current lexical scope.
231    pub fn current_items_mut(&mut self) -> &mut Items {
232        &mut self.current_lexical_scope_mut().items
233    }
234
235    pub fn current_lexical_scope_id(&self) -> LexicalScopeId {
236        self.current_lexical_scope_id
237    }
238
239    /// Enters the scope with the given span in the module's lexical scope hierarchy.
240    pub fn enter_lexical_scope(
241        &mut self,
242        handler: &Handler,
243        span: Span,
244    ) -> Result<LexicalScopeId, ErrorEmitted> {
245        let id_opt = self.lexical_scopes_spans.get(&span);
246        match id_opt {
247            Some(id) => {
248                let visitor_parent = self.current_lexical_scope_id;
249                self.current_lexical_scope_id = *id;
250                self.current_lexical_scope_mut().visitor_parent = Some(visitor_parent);
251
252                Ok(self.current_lexical_scope_id)
253            }
254            None => Err(handler.emit_err(CompileError::Internal(
255                "Could not find a valid lexical scope for this source location.",
256                span.clone(),
257            ))),
258        }
259    }
260
261    /// Pushes a new scope to the module's lexical scope hierarchy.
262    pub fn push_new_lexical_scope(
263        &mut self,
264        span: Span,
265        declaration: Option<ResolvedDeclaration>,
266    ) -> LexicalScopeId {
267        let previous_scope_id = self.current_lexical_scope_id();
268        let previous_scope = self.lexical_scopes.get(previous_scope_id).unwrap();
269        let new_scoped_id = {
270            self.lexical_scopes.push(LexicalScope {
271                parent: Some(previous_scope_id),
272                visitor_parent: Some(previous_scope_id),
273                items: Items {
274                    symbols_unique_while_collecting_unifications: previous_scope
275                        .items
276                        .symbols_unique_while_collecting_unifications
277                        .clone(),
278                    ..Default::default()
279                },
280                declaration,
281                ..Default::default()
282            });
283            self.lexical_scopes.len() - 1
284        };
285        let previous_scope = self.lexical_scopes.get_mut(previous_scope_id).unwrap();
286        previous_scope.children.push(new_scoped_id);
287        self.current_lexical_scope_id = new_scoped_id;
288        self.lexical_scopes_spans.insert(span, new_scoped_id);
289        new_scoped_id
290    }
291
292    /// Pops the current scope from the module's lexical scope hierarchy.
293    pub fn pop_lexical_scope(&mut self) {
294        let parent_scope_id = self.current_lexical_scope().visitor_parent;
295        self.current_lexical_scope_id = parent_scope_id.unwrap(); // panics if pops do not match pushes
296    }
297
298    pub fn walk_scope_chain_early_return<T>(
299        &self,
300        mut f: impl FnMut(&LexicalScope) -> Result<Option<T>, ErrorEmitted>,
301    ) -> Result<Option<T>, ErrorEmitted> {
302        let mut lexical_scope_opt = Some(self.current_lexical_scope());
303        while let Some(lexical_scope) = lexical_scope_opt {
304            let result = f(lexical_scope)?;
305            if let Some(result) = result {
306                return Ok(Some(result));
307            }
308            if let Some(parent_scope_id) = lexical_scope.parent {
309                lexical_scope_opt = self.get_lexical_scope(parent_scope_id);
310            } else {
311                lexical_scope_opt = None;
312            }
313        }
314        Ok(None)
315    }
316
317    pub fn walk_scope_chain(&self, mut f: impl FnMut(&LexicalScope)) {
318        let mut lexical_scope_opt = Some(self.current_lexical_scope());
319        while let Some(lexical_scope) = lexical_scope_opt {
320            f(lexical_scope);
321            if let Some(parent_scope_id) = lexical_scope.parent {
322                lexical_scope_opt = self.get_lexical_scope(parent_scope_id);
323            } else {
324                lexical_scope_opt = None;
325            }
326        }
327    }
328
329    pub fn get_items_for_type(
330        &self,
331        engines: &Engines,
332        type_id: TypeId,
333    ) -> Vec<ResolvedTraitImplItem> {
334        TraitMap::get_items_for_type(self, engines, type_id)
335    }
336
337    pub fn resolve_symbol(
338        &self,
339        handler: &Handler,
340        engines: &Engines,
341        symbol: &Ident,
342    ) -> Result<(ResolvedDeclaration, ModulePathBuf), ErrorEmitted> {
343        let mut last_handler = Handler::default();
344        let ret = self.walk_scope_chain_early_return(|lexical_scope| {
345            last_handler = Handler::default();
346            Ok(lexical_scope
347                .items
348                .resolve_symbol(&last_handler, engines, symbol, &self.mod_path)
349                .ok()
350                .flatten())
351        })?;
352
353        handler.append(last_handler);
354
355        if let Some(ret) = ret {
356            Ok(ret)
357        } else {
358            // Symbol not found
359            Err(handler.emit_err(CompileError::SymbolNotFound {
360                name: symbol.clone(),
361                span: symbol.span(),
362            }))
363        }
364    }
365
366    pub fn get_methods_for_type(
367        &self,
368        engines: &Engines,
369        type_id: TypeId,
370    ) -> Vec<ResolvedFunctionDecl> {
371        self.get_items_for_type(engines, type_id)
372            .into_iter()
373            .filter_map(|item| match item {
374                ResolvedTraitImplItem::Parsed(_) => unreachable!(),
375                ResolvedTraitImplItem::Typed(item) => match item {
376                    ty::TyTraitItem::Fn(decl_ref) => Some(ResolvedFunctionDecl::Typed(decl_ref)),
377                    ty::TyTraitItem::Constant(_decl_ref) => None,
378                    ty::TyTraitItem::Type(_decl_ref) => None,
379                },
380            })
381            .collect::<Vec<_>>()
382    }
383}
384
385/// Create a ModuleNotFound error.
386/// If skip_package_name is true, then the package name is not emitted as part of the error
387/// message. This is used when the module was supposed to be found in the current package rather
388/// than in an external one.
389pub fn module_not_found(path: &[Ident], skip_package_name: bool) -> CompileError {
390    CompileError::ModuleNotFound {
391        span: path
392            .iter()
393            .skip(if skip_package_name { 1 } else { 0 })
394            .fold(path.last().unwrap().span(), |acc, this_one| {
395                if acc.source_id() == this_one.span().source_id() {
396                    Span::join(acc, &this_one.span())
397                } else {
398                    acc
399                }
400            }),
401        name: path
402            .iter()
403            .skip(if skip_package_name { 1 } else { 0 })
404            .map(|x| x.as_str())
405            .collect::<Vec<_>>()
406            .join("::"),
407    }
408}