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}