sway_core/semantic_analysis/
symbol_collection_context.rs

1use crate::{
2    language::{parsed::Declaration, Visibility},
3    namespace::{LexicalScopeId, ModulePath, ResolvedDeclaration},
4    semantic_analysis::Namespace,
5    Engines,
6};
7use sway_error::handler::{ErrorEmitted, Handler};
8use sway_types::{span::Span, Ident};
9
10use super::{namespace::Items, ConstShadowingMode, GenericShadowingMode};
11
12#[derive(Clone)]
13/// Contextual state tracked and accumulated throughout symbol collecting.
14pub struct SymbolCollectionContext {
15    /// The namespace context accumulated throughout symbol collecting.
16    pub(crate) namespace: Namespace,
17
18    /// Whether or not a const declaration shadows previous const declarations sequentially.
19    ///
20    /// This is `Sequential` while checking const declarations in functions, otherwise `ItemStyle`.
21    const_shadowing_mode: ConstShadowingMode,
22    /// Whether or not a generic type parameters shadows previous generic type parameters.
23    ///
24    /// This is `Disallow` everywhere except while checking type parameters bounds in struct instantiation.
25    generic_shadowing_mode: GenericShadowingMode,
26}
27
28impl SymbolCollectionContext {
29    /// Initialize a context at the top-level of a module with its namespace.
30    pub fn new(namespace: Namespace) -> Self {
31        Self {
32            namespace,
33            const_shadowing_mode: ConstShadowingMode::ItemStyle,
34            generic_shadowing_mode: GenericShadowingMode::Disallow,
35        }
36    }
37
38    /// Scope the `CollectionContext` with a new lexical scope.
39    pub fn scoped<T>(
40        &mut self,
41        engines: &Engines,
42        span: Span,
43        decl: Option<Declaration>,
44        with_scoped_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result<T, ErrorEmitted>,
45    ) -> (Result<T, ErrorEmitted>, LexicalScopeId) {
46        let decl = decl.map(ResolvedDeclaration::Parsed);
47        let lexical_scope_id: LexicalScopeId =
48            self.namespace.current_module_mut().write(engines, |m| {
49                m.push_new_lexical_scope(span.clone(), decl.clone())
50            });
51        let ret = with_scoped_ctx(self);
52        self.namespace
53            .current_module_mut()
54            .write(engines, |m| m.pop_lexical_scope());
55        (ret, lexical_scope_id)
56    }
57
58    /// Enter the lexical scope corresponding to the given span and produce a
59    /// collection context ready for collecting its content.
60    ///
61    /// Returns the result of the given `with_ctx` function.
62    pub fn enter_lexical_scope<T>(
63        &mut self,
64        handler: &Handler,
65        engines: &Engines,
66        span: Span,
67        with_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result<T, ErrorEmitted>,
68    ) -> Result<T, ErrorEmitted> {
69        self.namespace
70            .current_module_mut()
71            .write(engines, |m| m.enter_lexical_scope(handler, span.clone()))?;
72        let ret = with_ctx(self);
73        self.namespace
74            .current_module_mut()
75            .write(engines, |m| m.pop_lexical_scope());
76        ret
77    }
78
79    /// Enter the submodule with the given name and produce a collection context ready for
80    /// collecting its content.
81    ///
82    /// Returns the result of the given `with_submod_ctx` function.
83    pub fn enter_submodule<T>(
84        &mut self,
85        handler: &Handler,
86        engines: &Engines,
87        mod_name: Ident,
88        visibility: Visibility,
89        module_span: Span,
90        with_submod_ctx: impl FnOnce(&mut SymbolCollectionContext) -> T,
91    ) -> Result<T, ErrorEmitted> {
92        self.namespace
93            .push_submodule(handler, engines, mod_name, visibility, module_span, true)?;
94        //let Self { namespace, .. } = self;
95        //let mut submod_ns = namespace.enter_submodule(mod_name, visibility, module_span);
96        let ret = with_submod_ctx(self);
97        self.namespace.pop_submodule();
98        Ok(ret)
99    }
100
101    /// Short-hand for calling [Items::insert_parsed_symbol].
102    pub(crate) fn insert_parsed_symbol(
103        &mut self,
104        handler: &Handler,
105        engines: &Engines,
106        name: Ident,
107        item: Declaration,
108    ) -> Result<(), ErrorEmitted> {
109        self.namespace.current_module_mut().write(engines, |m| {
110            Items::insert_parsed_symbol(
111                handler,
112                engines,
113                m,
114                name.clone(),
115                item.clone(),
116                self.const_shadowing_mode,
117                self.generic_shadowing_mode,
118            )
119        })
120    }
121
122    /// Returns a mutable reference to the current namespace.
123    pub fn namespace_mut(&mut self) -> &mut Namespace {
124        &mut self.namespace
125    }
126
127    /// Returns a reference to the current namespace.
128    pub fn namespace(&self) -> &Namespace {
129        &self.namespace
130    }
131
132    /// Short-hand for performing a [Module::star_import] with `mod_path` as the destination.
133    pub(crate) fn star_import(
134        &mut self,
135        handler: &Handler,
136        engines: &Engines,
137        src: &ModulePath,
138        visibility: Visibility,
139    ) -> Result<(), ErrorEmitted> {
140        self.namespace_mut()
141            .star_import_to_current_module(handler, engines, src, visibility)
142    }
143
144    /// Short-hand for performing a [Module::variant_star_import] with `mod_path` as the destination.
145    pub(crate) fn variant_star_import(
146        &mut self,
147        handler: &Handler,
148        engines: &Engines,
149        src: &ModulePath,
150        enum_name: &Ident,
151        visibility: Visibility,
152    ) -> Result<(), ErrorEmitted> {
153        self.namespace_mut()
154            .variant_star_import_to_current_module(handler, engines, src, enum_name, visibility)
155    }
156
157    /// Short-hand for performing a [Module::self_import] with `mod_path` as the destination.
158    pub(crate) fn self_import(
159        &mut self,
160        handler: &Handler,
161        engines: &Engines,
162        src: &ModulePath,
163        alias: Option<Ident>,
164        visibility: Visibility,
165    ) -> Result<(), ErrorEmitted> {
166        self.namespace_mut()
167            .self_import_to_current_module(handler, engines, src, alias, visibility)
168    }
169
170    /// Short-hand for performing a [Module::item_import] with `mod_path` as the destination.
171    pub(crate) fn item_import(
172        &mut self,
173        handler: &Handler,
174        engines: &Engines,
175        src: &ModulePath,
176        item: &Ident,
177        alias: Option<Ident>,
178        visibility: Visibility,
179    ) -> Result<(), ErrorEmitted> {
180        self.namespace_mut()
181            .item_import_to_current_module(handler, engines, src, item, alias, visibility)
182    }
183
184    /// Short-hand for performing a [Module::variant_import] with `mod_path` as the destination.
185    #[allow(clippy::too_many_arguments)]
186    pub(crate) fn variant_import(
187        &mut self,
188        handler: &Handler,
189        engines: &Engines,
190        src: &ModulePath,
191        enum_name: &Ident,
192        variant_name: &Ident,
193        alias: Option<Ident>,
194        visibility: Visibility,
195    ) -> Result<(), ErrorEmitted> {
196        self.namespace_mut().variant_import_to_current_module(
197            handler,
198            engines,
199            src,
200            enum_name,
201            variant_name,
202            alias,
203            visibility,
204        )
205    }
206}