sway_core/semantic_analysis/
symbol_resolve_context.rs

1use crate::{
2    engine_threading::*,
3    language::{CallPath, Visibility},
4    namespace::ResolvedDeclaration,
5    semantic_analysis::{ast_node::ConstShadowingMode, Namespace},
6    type_system::TypeId,
7};
8use sway_error::handler::{ErrorEmitted, Handler};
9use sway_types::{span::Span, Ident};
10
11use super::{
12    symbol_collection_context::SymbolCollectionContext,
13    type_resolve::{resolve_call_path, VisibilityCheck},
14    GenericShadowingMode,
15};
16
17/// Contextual state tracked and accumulated throughout symbol resolving.
18pub struct SymbolResolveContext<'a> {
19    /// The namespace context accumulated throughout symbol resolving.
20    ///
21    /// Internally, this includes:
22    ///
23    /// - The `root` module from which all other modules maybe be accessed using absolute paths.
24    /// - The `init` module used to initialize submodule namespaces.
25    /// - A `mod_path` that represents the current module being type-checked. This is automatically
26    ///   updated upon entering/exiting submodules via the `enter_submodule` method.
27    pub(crate) engines: &'a Engines,
28    pub(crate) symbol_collection_ctx: &'a mut SymbolCollectionContext,
29
30    // The following set of fields are intentionally private. When a `SymbolResolveContext` is passed
31    // into a new node during symbol resolving, these fields should be updated using the `with_*`
32    // methods which provides a new `SymbolResolveContext`, ensuring we don't leak our changes into
33    // the parent nodes.
34    /// While symbol resolving an `impl` (whether inherent or for a `trait`/`abi`) this represents the
35    /// type for which we are implementing. For example in `impl Foo {}` or `impl Trait for Foo
36    /// {}`, this represents the type ID of `Foo`.
37    self_type: Option<TypeId>,
38    /// Whether or not a const declaration shadows previous const declarations sequentially.
39    ///
40    /// This is `Sequential` while checking const declarations in functions, otherwise `ItemStyle`.
41    const_shadowing_mode: ConstShadowingMode,
42    /// Whether or not a generic type parameters shadows previous generic type parameters.
43    ///
44    /// This is `Disallow` everywhere except while checking type parameters bounds in struct instantiation.
45    generic_shadowing_mode: GenericShadowingMode,
46}
47
48impl<'a> SymbolResolveContext<'a> {
49    /// Initialize a symbol resolving context with a namespace.
50    pub fn new(
51        engines: &'a Engines,
52        symbol_collection_ctx: &'a mut SymbolCollectionContext,
53    ) -> Self {
54        Self {
55            engines,
56            symbol_collection_ctx,
57            self_type: None,
58            const_shadowing_mode: ConstShadowingMode::ItemStyle,
59            generic_shadowing_mode: GenericShadowingMode::Disallow,
60        }
61    }
62
63    /// Create a new context that mutably borrows the inner `namespace` with a lifetime bound by
64    /// `self`.
65    ///
66    /// This is particularly useful when symbol resolving a node that has more than one child node
67    /// (very often the case). By taking the context with the namespace lifetime bound to `self`
68    /// rather than the original namespace reference, we instead restrict the returned context to
69    /// the local scope and avoid consuming the original context when providing context to the
70    /// first visited child node.
71    pub fn by_ref(&mut self) -> SymbolResolveContext<'_> {
72        SymbolResolveContext {
73            engines: self.engines,
74            symbol_collection_ctx: self.symbol_collection_ctx,
75            self_type: self.self_type,
76            const_shadowing_mode: self.const_shadowing_mode,
77            generic_shadowing_mode: self.generic_shadowing_mode,
78        }
79    }
80
81    /// Scope the `SymbolResolveContext` with a new namespace lexical scope.
82    pub fn enter_lexical_scope<T>(
83        self,
84        handler: &Handler,
85        span: Span,
86        with_scoped_ctx: impl FnOnce(SymbolResolveContext) -> Result<T, ErrorEmitted>,
87    ) -> Result<T, ErrorEmitted> {
88        let engines = self.engines;
89        self.symbol_collection_ctx.enter_lexical_scope(
90            handler,
91            engines,
92            span,
93            |sub_scope_collect_ctx| {
94                let sub_scope_resolve_ctx =
95                    SymbolResolveContext::new(engines, sub_scope_collect_ctx);
96                with_scoped_ctx(sub_scope_resolve_ctx)
97            },
98        )
99    }
100
101    /// Enter the submodule with the given name and a symbol resolve context ready for
102    /// symbol resolving its content.
103    ///
104    /// Returns the result of the given `with_submod_ctx` function.
105    pub fn enter_submodule<T>(
106        self,
107        handler: &Handler,
108        mod_name: Ident,
109        visibility: Visibility,
110        module_span: Span,
111        with_submod_ctx: impl FnOnce(SymbolResolveContext) -> T,
112    ) -> Result<T, ErrorEmitted> {
113        let engines = self.engines;
114        self.symbol_collection_ctx.enter_submodule(
115            handler,
116            engines,
117            mod_name,
118            visibility,
119            module_span,
120            |submod_collect_ctx| {
121                let submod_ctx = SymbolResolveContext::new(engines, submod_collect_ctx);
122                with_submod_ctx(submod_ctx)
123            },
124        )
125    }
126
127    /// Returns a mutable reference to the current namespace.
128    pub fn namespace_mut(&mut self) -> &mut Namespace {
129        &mut self.symbol_collection_ctx.namespace
130    }
131
132    /// Returns a reference to the current namespace.
133    pub fn namespace(&self) -> &Namespace {
134        &self.symbol_collection_ctx.namespace
135    }
136
137    /// Map this `SymbolResolveContext` instance to a new one with the given const shadowing `mode`.
138    #[allow(unused)]
139    pub(crate) fn with_const_shadowing_mode(
140        self,
141        const_shadowing_mode: ConstShadowingMode,
142    ) -> Self {
143        Self {
144            const_shadowing_mode,
145            ..self
146        }
147    }
148
149    /// Map this `SymbolResolveContext` instance to a new one with the given generic shadowing `mode`.
150    #[allow(unused)]
151    pub(crate) fn with_generic_shadowing_mode(
152        self,
153        generic_shadowing_mode: GenericShadowingMode,
154    ) -> Self {
155        Self {
156            generic_shadowing_mode,
157            ..self
158        }
159    }
160
161    // A set of accessor methods. We do this rather than making the fields `pub` in order to ensure
162    // that these are only updated via the `with_*` methods that produce a new `SymbolResolveContext`.
163    #[allow(unused)]
164    pub(crate) fn self_type(&self) -> Option<TypeId> {
165        self.self_type
166    }
167
168    #[allow(unused)]
169    pub(crate) fn const_shadowing_mode(&self) -> ConstShadowingMode {
170        self.const_shadowing_mode
171    }
172
173    #[allow(unused)]
174    pub(crate) fn generic_shadowing_mode(&self) -> GenericShadowingMode {
175        self.generic_shadowing_mode
176    }
177
178    /// Get the engines needed for engine threading.
179    pub(crate) fn engines(&self) -> &'a Engines {
180        self.engines
181    }
182
183    /// Short-hand for calling [Root::resolve_call_path_with_visibility_check] on `root` with the `mod_path`.
184    pub(crate) fn resolve_call_path_with_visibility_check(
185        &self,
186        handler: &Handler,
187        call_path: &CallPath,
188    ) -> Result<ResolvedDeclaration, ErrorEmitted> {
189        resolve_call_path(
190            handler,
191            self.engines(),
192            self.namespace(),
193            &self.namespace().current_mod_path,
194            call_path,
195            self.self_type(),
196            VisibilityCheck::Yes,
197        )
198    }
199}