sway_core/semantic_analysis/namespace/
module.rsuse crate::{
engine_threading::Engines,
language::{
ty::{self},
Visibility,
},
Ident, TypeId,
};
use super::{
lexical_scope::{Items, LexicalScope, ResolvedFunctionDecl},
LexicalScopeId, ModuleName, ModulePath, ModulePathBuf, ResolvedDeclaration,
ResolvedTraitImplItem, TraitMap,
};
use rustc_hash::FxHasher;
use std::{collections::HashMap, hash::BuildHasherDefault};
use sway_error::handler::Handler;
use sway_error::{error::CompileError, handler::ErrorEmitted};
use sway_types::{span::Span, Spanned};
#[derive(Clone, Debug)]
pub struct Module {
submodules: im::HashMap<ModuleName, Module, BuildHasherDefault<FxHasher>>,
pub lexical_scopes: Vec<LexicalScope>,
pub current_lexical_scope_id: LexicalScopeId,
pub lexical_scopes_spans: HashMap<Span, LexicalScopeId>,
name: Ident,
visibility: Visibility,
span: Option<Span>,
mod_path: ModulePathBuf,
}
impl Module {
pub(super) fn new(
name: Ident,
visibility: Visibility,
span: Option<Span>,
parent_mod_path: &ModulePathBuf,
) -> Self {
let mut mod_path = parent_mod_path.clone();
mod_path.push(name.clone());
Self {
visibility,
submodules: Default::default(),
lexical_scopes: vec![LexicalScope::default()],
lexical_scopes_spans: Default::default(),
current_lexical_scope_id: 0,
name,
span,
mod_path,
}
}
pub fn name(&self) -> &Ident {
&self.name
}
pub fn visibility(&self) -> &Visibility {
&self.visibility
}
pub fn span(&self) -> &Option<Span> {
&self.span
}
pub fn set_span(&mut self, span: Span) {
self.span = Some(span);
}
pub(super) fn add_new_submodule(
&mut self,
name: &Ident,
visibility: Visibility,
span: Option<Span>,
) {
let module = Self::new(name.clone(), visibility, span, &self.mod_path);
self.submodules.insert(name.to_string(), module);
}
pub fn read<R>(&self, _engines: &crate::Engines, mut f: impl FnMut(&Module) -> R) -> R {
f(self)
}
pub fn write<R>(
&mut self,
_engines: &crate::Engines,
mut f: impl FnMut(&mut Module) -> R,
) -> R {
f(self)
}
pub fn mod_path(&self) -> &ModulePath {
self.mod_path.as_slice()
}
pub fn mod_path_buf(&self) -> ModulePathBuf {
self.mod_path.clone()
}
pub fn submodules(&self) -> &im::HashMap<ModuleName, Module, BuildHasherDefault<FxHasher>> {
&self.submodules
}
pub fn has_submodule(&self, name: &Ident) -> bool {
self.submodule(&[name.clone()]).is_some()
}
pub fn submodules_mut(
&mut self,
) -> &mut im::HashMap<ModuleName, Module, BuildHasherDefault<FxHasher>> {
&mut self.submodules
}
pub fn submodule(&self, path: &ModulePath) -> Option<&Module> {
let mut module = self;
for ident in path.iter() {
match module.submodules.get(ident.as_str()) {
Some(ns) => module = ns,
None => return None,
}
}
Some(module)
}
pub fn submodule_mut(&mut self, path: &ModulePath) -> Option<&mut Module> {
let mut module = self;
for ident in path.iter() {
match module.submodules.get_mut(ident.as_str()) {
Some(ns) => module = ns,
None => return None,
}
}
Some(module)
}
pub(crate) fn lookup_submodule(
&self,
handler: &Handler,
path: &[Ident],
) -> Result<&Module, ErrorEmitted> {
match self.submodule(path) {
None => Err(handler.emit_err(module_not_found(path, true))),
Some(module) => Ok(module),
}
}
pub fn root_lexical_scope_id(&self) -> LexicalScopeId {
0
}
pub fn root_lexical_scope(&self) -> &LexicalScope {
self.lexical_scopes
.get(self.root_lexical_scope_id())
.unwrap()
}
pub fn get_lexical_scope(&self, id: LexicalScopeId) -> Option<&LexicalScope> {
self.lexical_scopes.get(id)
}
pub fn get_lexical_scope_mut(&mut self, id: LexicalScopeId) -> Option<&mut LexicalScope> {
self.lexical_scopes.get_mut(id)
}
pub fn current_lexical_scope(&self) -> &LexicalScope {
self.lexical_scopes
.get(self.current_lexical_scope_id)
.unwrap()
}
pub fn current_lexical_scope_mut(&mut self) -> &mut LexicalScope {
self.lexical_scopes
.get_mut(self.current_lexical_scope_id)
.unwrap()
}
pub fn current_items(&self) -> &Items {
&self.current_lexical_scope().items
}
pub fn root_items(&self) -> &Items {
&self.root_lexical_scope().items
}
pub fn current_items_mut(&mut self) -> &mut Items {
&mut self.current_lexical_scope_mut().items
}
pub fn current_lexical_scope_id(&self) -> LexicalScopeId {
self.current_lexical_scope_id
}
pub fn enter_lexical_scope(
&mut self,
handler: &Handler,
span: Span,
) -> Result<LexicalScopeId, ErrorEmitted> {
let id_opt = self.lexical_scopes_spans.get(&span);
match id_opt {
Some(id) => {
let visitor_parent = self.current_lexical_scope_id;
self.current_lexical_scope_id = *id;
self.current_lexical_scope_mut().visitor_parent = Some(visitor_parent);
Ok(self.current_lexical_scope_id)
}
None => Err(handler.emit_err(CompileError::Internal(
"Could not find a valid lexical scope for this source location.",
span.clone(),
))),
}
}
pub fn push_new_lexical_scope(
&mut self,
span: Span,
declaration: Option<ResolvedDeclaration>,
) -> LexicalScopeId {
let previous_scope_id = self.current_lexical_scope_id();
let previous_scope = self.lexical_scopes.get(previous_scope_id).unwrap();
let new_scoped_id = {
self.lexical_scopes.push(LexicalScope {
parent: Some(previous_scope_id),
visitor_parent: Some(previous_scope_id),
items: Items {
symbols_unique_while_collecting_unifications: previous_scope
.items
.symbols_unique_while_collecting_unifications
.clone(),
..Default::default()
},
declaration,
..Default::default()
});
self.lexical_scopes.len() - 1
};
let previous_scope = self.lexical_scopes.get_mut(previous_scope_id).unwrap();
previous_scope.children.push(new_scoped_id);
self.current_lexical_scope_id = new_scoped_id;
self.lexical_scopes_spans.insert(span, new_scoped_id);
new_scoped_id
}
pub fn pop_lexical_scope(&mut self) {
let parent_scope_id = self.current_lexical_scope().visitor_parent;
self.current_lexical_scope_id = parent_scope_id.unwrap(); }
pub fn walk_scope_chain<T>(
&self,
mut f: impl FnMut(&LexicalScope) -> Result<Option<T>, ErrorEmitted>,
) -> Result<Option<T>, ErrorEmitted> {
let mut lexical_scope_opt = Some(self.current_lexical_scope());
while let Some(lexical_scope) = lexical_scope_opt {
let result = f(lexical_scope)?;
if let Some(result) = result {
return Ok(Some(result));
}
if let Some(parent_scope_id) = lexical_scope.parent {
lexical_scope_opt = self.get_lexical_scope(parent_scope_id);
} else {
lexical_scope_opt = None;
}
}
Ok(None)
}
pub fn walk_scope_chain_mut<T>(
&mut self,
mut f: impl FnMut(&mut LexicalScope) -> Result<Option<T>, ErrorEmitted>,
) -> Result<Option<T>, ErrorEmitted> {
let mut lexical_scope_opt = Some(self.current_lexical_scope_mut());
while let Some(lexical_scope) = lexical_scope_opt {
let result = f(lexical_scope)?;
if let Some(result) = result {
return Ok(Some(result));
}
if let Some(parent_scope_id) = lexical_scope.parent {
lexical_scope_opt = self.get_lexical_scope_mut(parent_scope_id);
} else {
lexical_scope_opt = None;
}
}
Ok(None)
}
pub fn get_items_for_type(
&self,
engines: &Engines,
type_id: TypeId,
) -> Vec<ResolvedTraitImplItem> {
TraitMap::get_items_for_type(self, engines, type_id)
}
pub fn resolve_symbol(
&self,
handler: &Handler,
engines: &Engines,
symbol: &Ident,
) -> Result<(ResolvedDeclaration, ModulePathBuf), ErrorEmitted> {
let mut last_handler = Handler::default();
let ret = self.walk_scope_chain(|lexical_scope| {
last_handler = Handler::default();
Ok(lexical_scope
.items
.resolve_symbol(&last_handler, engines, symbol, &self.mod_path)
.ok()
.flatten())
})?;
handler.append(last_handler);
if let Some(ret) = ret {
Ok(ret)
} else {
Err(handler.emit_err(CompileError::SymbolNotFound {
name: symbol.clone(),
span: symbol.span(),
}))
}
}
pub fn get_methods_for_type(
&self,
engines: &Engines,
type_id: TypeId,
) -> Vec<ResolvedFunctionDecl> {
self.get_items_for_type(engines, type_id)
.into_iter()
.filter_map(|item| match item {
ResolvedTraitImplItem::Parsed(_) => unreachable!(),
ResolvedTraitImplItem::Typed(item) => match item {
ty::TyTraitItem::Fn(decl_ref) => Some(ResolvedFunctionDecl::Typed(decl_ref)),
ty::TyTraitItem::Constant(_decl_ref) => None,
ty::TyTraitItem::Type(_decl_ref) => None,
},
})
.collect::<Vec<_>>()
}
}
pub fn module_not_found(path: &[Ident], skip_package_name: bool) -> CompileError {
CompileError::ModuleNotFound {
span: path
.iter()
.skip(if skip_package_name { 1 } else { 0 })
.fold(path.last().unwrap().span(), |acc, this_one| {
if acc.source_id() == this_one.span().source_id() {
Span::join(acc, &this_one.span())
} else {
acc
}
}),
name: path
.iter()
.skip(if skip_package_name { 1 } else { 0 })
.map(|x| x.as_str())
.collect::<Vec<_>>()
.join("::"),
}
}