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 append_items_for_type(
330        &self,
331        engines: &Engines,
332        type_id: TypeId,
333        items: &mut Vec<ResolvedTraitImplItem>,
334    ) {
335        TraitMap::append_items_for_type(self, engines, type_id, items)
336    }
337
338    pub fn resolve_symbol(
339        &self,
340        handler: &Handler,
341        engines: &Engines,
342        symbol: &Ident,
343    ) -> Result<(ResolvedDeclaration, ModulePathBuf), ErrorEmitted> {
344        let mut last_handler = Handler::default();
345        let ret = self.walk_scope_chain_early_return(|lexical_scope| {
346            last_handler = Handler::default();
347            Ok(lexical_scope
348                .items
349                .resolve_symbol(&last_handler, engines, symbol, &self.mod_path)
350                .ok()
351                .flatten())
352        })?;
353
354        handler.append(last_handler);
355
356        if let Some(ret) = ret {
357            Ok(ret)
358        } else {
359            // Symbol not found
360            Err(handler.emit_err(CompileError::SymbolNotFound {
361                name: symbol.clone(),
362                span: symbol.span(),
363            }))
364        }
365    }
366
367    pub fn get_methods_for_type(
368        &self,
369        engines: &Engines,
370        type_id: TypeId,
371    ) -> Vec<ResolvedFunctionDecl> {
372        let mut items = vec![];
373        self.append_items_for_type(engines, type_id, &mut items);
374
375        items
376            .into_iter()
377            .filter_map(|item| match item {
378                ResolvedTraitImplItem::Parsed(_) => unreachable!(),
379                ResolvedTraitImplItem::Typed(item) => match item {
380                    ty::TyTraitItem::Fn(decl_ref) => Some(ResolvedFunctionDecl::Typed(decl_ref)),
381                    ty::TyTraitItem::Constant(_decl_ref) => None,
382                    ty::TyTraitItem::Type(_decl_ref) => None,
383                },
384            })
385            .collect::<Vec<_>>()
386    }
387}
388
389/// Create a ModuleNotFound error.
390/// If skip_package_name is true, then the package name is not emitted as part of the error
391/// message. This is used when the module was supposed to be found in the current package rather
392/// than in an external one.
393pub fn module_not_found(path: &[Ident], skip_package_name: bool) -> CompileError {
394    CompileError::ModuleNotFound {
395        span: path
396            .iter()
397            .skip(if skip_package_name { 1 } else { 0 })
398            .fold(path.last().unwrap().span(), |acc, this_one| {
399                if acc.source_id() == this_one.span().source_id() {
400                    Span::join(acc, &this_one.span())
401                } else {
402                    acc
403                }
404            }),
405        name: path
406            .iter()
407            .skip(if skip_package_name { 1 } else { 0 })
408            .map(|x| x.as_str())
409            .collect::<Vec<_>>()
410            .join("::"),
411    }
412}