use std::fmt;
use super::{
module::Module, namespace::Namespace, trait_map::TraitMap, Ident, ResolvedTraitImplItem,
};
use crate::{
decl_engine::{DeclEngine, DeclRef},
engine_threading::*,
language::{
parsed::*,
ty::{self, StructDecl, TyDecl, TyTraitItem},
CallPath, Visibility,
},
namespace::{ModulePath, ModulePathBuf},
TypeId, TypeInfo,
};
use sway_error::{
error::CompileError,
handler::{ErrorEmitted, Handler},
};
use sway_types::{Named, Spanned};
use sway_utils::iter_prefixes;
#[derive(Clone, Debug)]
pub enum ResolvedDeclaration {
Parsed(Declaration),
Typed(ty::TyDecl),
}
impl DisplayWithEngines for ResolvedDeclaration {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
match self {
ResolvedDeclaration::Parsed(decl) => DisplayWithEngines::fmt(decl, f, engines),
ResolvedDeclaration::Typed(decl) => DisplayWithEngines::fmt(decl, f, engines),
}
}
}
impl DebugWithEngines for ResolvedDeclaration {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
match self {
ResolvedDeclaration::Parsed(decl) => DebugWithEngines::fmt(decl, f, engines),
ResolvedDeclaration::Typed(decl) => DebugWithEngines::fmt(decl, f, engines),
}
}
}
impl PartialEqWithEngines for ResolvedDeclaration {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
match (self, other) {
(ResolvedDeclaration::Parsed(lhs), ResolvedDeclaration::Parsed(rhs)) => {
lhs.eq(rhs, ctx)
}
(ResolvedDeclaration::Typed(lhs), ResolvedDeclaration::Typed(rhs)) => lhs.eq(rhs, ctx),
(ResolvedDeclaration::Parsed(_lhs), ResolvedDeclaration::Typed(_rhs)) => false,
(ResolvedDeclaration::Typed(_lhs), ResolvedDeclaration::Parsed(_rhs)) => false,
}
}
}
impl ResolvedDeclaration {
pub fn is_typed(&self) -> bool {
match self {
ResolvedDeclaration::Parsed(_) => false,
ResolvedDeclaration::Typed(_) => true,
}
}
pub fn resolve_parsed(self, decl_engine: &DeclEngine) -> Declaration {
match self {
ResolvedDeclaration::Parsed(decl) => decl,
ResolvedDeclaration::Typed(ty_decl) => ty_decl
.get_parsed_decl(decl_engine)
.expect("expecting valid parsed declaration"),
}
}
pub fn expect_parsed(self) -> Declaration {
match self {
ResolvedDeclaration::Parsed(decl) => decl,
ResolvedDeclaration::Typed(_ty_decl) => panic!(),
}
}
pub fn expect_typed(self) -> ty::TyDecl {
match self {
ResolvedDeclaration::Parsed(_) => panic!(),
ResolvedDeclaration::Typed(ty_decl) => ty_decl,
}
}
pub fn expect_typed_ref(&self) -> &ty::TyDecl {
match self {
ResolvedDeclaration::Parsed(_) => panic!(),
ResolvedDeclaration::Typed(ty_decl) => ty_decl,
}
}
pub(crate) fn to_struct_decl(
&self,
handler: &Handler,
engines: &Engines,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
match self {
ResolvedDeclaration::Parsed(decl) => decl
.to_struct_decl(handler, engines)
.map(|id| ResolvedDeclaration::Parsed(Declaration::StructDeclaration(id))),
ResolvedDeclaration::Typed(decl) => decl.to_struct_decl(handler, engines).map(|id| {
ResolvedDeclaration::Typed(TyDecl::StructDecl(StructDecl { decl_id: id }))
}),
}
}
pub(crate) fn visibility(&self, engines: &Engines) -> Visibility {
match self {
ResolvedDeclaration::Parsed(decl) => decl.visibility(engines.pe()),
ResolvedDeclaration::Typed(decl) => decl.visibility(engines.de()),
}
}
fn span(&self, engines: &Engines) -> sway_types::Span {
match self {
ResolvedDeclaration::Parsed(decl) => decl.span(engines),
ResolvedDeclaration::Typed(decl) => decl.span(engines),
}
}
pub(crate) fn return_type(
&self,
handler: &Handler,
engines: &Engines,
) -> Result<TypeId, ErrorEmitted> {
match self {
ResolvedDeclaration::Parsed(_decl) => unreachable!(),
ResolvedDeclaration::Typed(decl) => decl.return_type(handler, engines),
}
}
fn is_trait(&self) -> bool {
match self {
ResolvedDeclaration::Parsed(decl) => {
matches!(decl, Declaration::TraitDeclaration(_))
}
ResolvedDeclaration::Typed(decl) => {
matches!(decl, TyDecl::TraitDecl(_))
}
}
}
}
#[derive(Clone, Debug, Default)]
pub struct Root {
pub(crate) module: Module,
}
impl Root {
pub fn star_import(
&mut self,
handler: &Handler,
engines: &Engines,
src: &ModulePath,
dst: &ModulePath,
visibility: Visibility,
) -> Result<(), ErrorEmitted> {
self.check_module_privacy(handler, engines, src)?;
let src_mod = self.module.lookup_submodule(handler, engines, src)?;
let mut decls_and_item_imports = vec![];
let get_path = |mod_path: Vec<Ident>| {
let mut is_external = false;
if let Some(submodule) = src_mod.submodule(engines, &[mod_path[0].clone()]) {
is_external = submodule.is_external
};
let mut path = src[..1].to_vec();
if is_external {
path = mod_path;
} else {
path.extend(mod_path);
}
path
};
for (symbol, decl) in src_mod.current_items().symbols.iter() {
if is_ancestor(src, dst) || decl.visibility(engines).is_public() {
decls_and_item_imports.push((symbol.clone(), decl.clone(), src.to_vec()));
}
}
for (symbol, (_, path, decl, src_visibility)) in
src_mod.current_items().use_item_synonyms.iter()
{
if src_visibility.is_public() {
decls_and_item_imports.push((symbol.clone(), decl.clone(), get_path(path.clone())))
}
}
let mut glob_imports = vec![];
for (symbol, bindings) in src_mod.current_items().use_glob_synonyms.iter() {
if !decls_and_item_imports
.iter()
.any(|(other_symbol, _, _)| symbol == other_symbol)
{
for (path, decl, src_visibility) in bindings.iter() {
if src_visibility.is_public() {
glob_imports.push((symbol.clone(), decl.clone(), get_path(path.clone())))
}
}
}
}
let implemented_traits = src_mod.current_items().implemented_traits.clone();
let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?;
dst_mod
.current_items_mut()
.implemented_traits
.extend(implemented_traits, engines);
decls_and_item_imports
.iter()
.chain(glob_imports.iter())
.for_each(|(symbol, decl, path)| {
dst_mod.current_items_mut().insert_glob_use_symbol(
engines,
symbol.clone(),
path.clone(),
decl,
visibility,
)
});
Ok(())
}
pub(crate) fn self_import(
&mut self,
handler: &Handler,
engines: &Engines,
src: &ModulePath,
dst: &ModulePath,
alias: Option<Ident>,
visibility: Visibility,
) -> Result<(), ErrorEmitted> {
let (last_item, src) = src.split_last().expect("guaranteed by grammar");
self.item_import(handler, engines, src, last_item, dst, alias, visibility)
}
fn item_lookup(
&self,
handler: &Handler,
engines: &Engines,
item: &Ident,
src: &ModulePath,
dst: &ModulePath,
) -> Result<(ResolvedDeclaration, ModulePathBuf), ErrorEmitted> {
let src_mod = self.module.lookup_submodule(handler, engines, src)?;
let src_items = src_mod.current_items();
let (decl, path, src_visibility) = if let Some(decl) = src_items.symbols.get(item) {
let visibility = if is_ancestor(src, dst) {
Visibility::Public
} else {
decl.visibility(engines)
};
(decl.clone(), src.to_vec(), visibility)
} else if let Some((_, path, decl, reexport)) = src_items.use_item_synonyms.get(item) {
(decl.clone(), path.clone(), *reexport)
} else if let Some(decls) = src_items.use_glob_synonyms.get(item) {
if decls.len() == 1 {
let (path, decl, reexport) = &decls[0];
(decl.clone(), path.clone(), *reexport)
} else if decls.is_empty() {
return Err(handler.emit_err(CompileError::Internal(
"The name {symbol} was bound in a star import, but no corresponding module paths were found",
item.span(),
)));
} else {
return Err(handler.emit_err(CompileError::SymbolWithMultipleBindings {
name: item.clone(),
paths: decls
.iter()
.map(|(path, decl, _)| {
let mut path_strs = path.iter().map(|x| x.as_str()).collect::<Vec<_>>();
if let TyDecl::EnumVariantDecl(ty::EnumVariantDecl {
enum_ref, ..
}) = decl.expect_typed_ref()
{
path_strs.push(enum_ref.name().as_str())
};
path_strs.join("::")
})
.collect(),
span: item.span(),
}));
}
} else {
return Err(handler.emit_err(CompileError::SymbolNotFound {
name: item.clone(),
span: item.span(),
}));
};
if !src_visibility.is_public() {
handler.emit_err(CompileError::ImportPrivateSymbol {
name: item.clone(),
span: item.span(),
});
}
Ok((decl, path))
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn item_import(
&mut self,
handler: &Handler,
engines: &Engines,
src: &ModulePath,
item: &Ident,
dst: &ModulePath,
alias: Option<Ident>,
visibility: Visibility,
) -> Result<(), ErrorEmitted> {
self.check_module_privacy(handler, engines, src)?;
let src_mod = self.module.lookup_submodule(handler, engines, src)?;
let (decl, path) = self.item_lookup(handler, engines, item, src, dst)?;
let mut impls_to_insert = TraitMap::default();
if decl.is_typed() {
if let Ok(type_id) = decl.return_type(&Handler::default(), engines) {
impls_to_insert.extend(
src_mod
.current_items()
.implemented_traits
.filter_by_type_item_import(
type_id,
engines,
super::CodeBlockFirstPass::No,
),
engines,
);
}
let decl_span = decl.span(engines);
if decl.is_trait() {
impls_to_insert.extend(
src_mod
.current_items()
.implemented_traits
.filter_by_trait_decl_span(decl_span),
engines,
);
}
}
let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?;
let check_name_clash = |name| {
if dst_mod.current_items().use_item_synonyms.contains_key(name) {
handler.emit_err(CompileError::ShadowsOtherSymbol { name: name.into() });
}
};
match alias {
Some(alias) => {
check_name_clash(&alias);
dst_mod
.current_items_mut()
.use_item_synonyms
.insert(alias.clone(), (Some(item.clone()), path, decl, visibility))
}
None => {
check_name_clash(item);
dst_mod
.current_items_mut()
.use_item_synonyms
.insert(item.clone(), (None, path, decl, visibility))
}
};
dst_mod
.current_items_mut()
.implemented_traits
.extend(impls_to_insert, engines);
Ok(())
}
#[allow(clippy::too_many_arguments)] pub(crate) fn variant_import(
&mut self,
handler: &Handler,
engines: &Engines,
src: &ModulePath,
enum_name: &Ident,
variant_name: &Ident,
dst: &ModulePath,
alias: Option<Ident>,
visibility: Visibility,
) -> Result<(), ErrorEmitted> {
self.check_module_privacy(handler, engines, src)?;
let decl_engine = engines.de();
let parsed_decl_engine = engines.pe();
let (decl, path) = self.item_lookup(handler, engines, enum_name, src, dst)?;
match decl {
ResolvedDeclaration::Parsed(decl) => {
if let Declaration::EnumDeclaration(decl_id) = decl {
let enum_decl = parsed_decl_engine.get_enum(&decl_id);
if let Some(variant_decl) =
enum_decl.variants.iter().find(|v| v.name == *variant_name)
{
let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?;
let check_name_clash = |name| {
if dst_mod.current_items().use_item_synonyms.contains_key(name) {
handler.emit_err(CompileError::ShadowsOtherSymbol {
name: name.into(),
});
}
};
match alias {
Some(alias) => {
check_name_clash(&alias);
dst_mod.current_items_mut().use_item_synonyms.insert(
alias.clone(),
(
Some(variant_name.clone()),
path,
ResolvedDeclaration::Parsed(
Declaration::EnumVariantDeclaration(
EnumVariantDeclaration {
enum_ref: decl_id,
variant_name: variant_name.clone(),
variant_decl_span: variant_decl.span.clone(),
},
),
),
visibility,
),
);
}
None => {
check_name_clash(variant_name);
dst_mod.current_items_mut().use_item_synonyms.insert(
variant_name.clone(),
(
None,
path,
ResolvedDeclaration::Parsed(
Declaration::EnumVariantDeclaration(
EnumVariantDeclaration {
enum_ref: decl_id,
variant_name: variant_name.clone(),
variant_decl_span: variant_decl.span.clone(),
},
),
),
visibility,
),
);
}
};
} else {
return Err(handler.emit_err(CompileError::SymbolNotFound {
name: variant_name.clone(),
span: variant_name.span(),
}));
}
}
}
ResolvedDeclaration::Typed(decl) => {
if let TyDecl::EnumDecl(ty::EnumDecl { decl_id, .. }) = decl {
let enum_decl = decl_engine.get_enum(&decl_id);
let enum_ref = DeclRef::new(
enum_decl.call_path.suffix.clone(),
decl_id,
enum_decl.span(),
);
if let Some(variant_decl) =
enum_decl.variants.iter().find(|v| v.name == *variant_name)
{
let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?;
let check_name_clash = |name| {
if dst_mod.current_items().use_item_synonyms.contains_key(name) {
handler.emit_err(CompileError::ShadowsOtherSymbol {
name: name.into(),
});
}
};
match alias {
Some(alias) => {
check_name_clash(&alias);
dst_mod.current_items_mut().use_item_synonyms.insert(
alias.clone(),
(
Some(variant_name.clone()),
path,
ResolvedDeclaration::Typed(TyDecl::EnumVariantDecl(
ty::EnumVariantDecl {
enum_ref: enum_ref.clone(),
variant_name: variant_name.clone(),
variant_decl_span: variant_decl.span.clone(),
},
)),
visibility,
),
);
}
None => {
check_name_clash(variant_name);
dst_mod.current_items_mut().use_item_synonyms.insert(
variant_name.clone(),
(
None,
path,
ResolvedDeclaration::Typed(TyDecl::EnumVariantDecl(
ty::EnumVariantDecl {
enum_ref: enum_ref.clone(),
variant_name: variant_name.clone(),
variant_decl_span: variant_decl.span.clone(),
},
)),
visibility,
),
);
}
};
} else {
return Err(handler.emit_err(CompileError::SymbolNotFound {
name: variant_name.clone(),
span: variant_name.span(),
}));
}
} else {
return Err(handler.emit_err(CompileError::Internal(
"Attempting to import variants of something that isn't an enum",
enum_name.span(),
)));
}
}
};
Ok(())
}
pub(crate) fn variant_star_import(
&mut self,
handler: &Handler,
engines: &Engines,
src: &ModulePath,
dst: &ModulePath,
enum_name: &Ident,
visibility: Visibility,
) -> Result<(), ErrorEmitted> {
self.check_module_privacy(handler, engines, src)?;
let parsed_decl_engine = engines.pe();
let decl_engine = engines.de();
let (decl, path) = self.item_lookup(handler, engines, enum_name, src, dst)?;
match decl {
ResolvedDeclaration::Parsed(Declaration::EnumDeclaration(decl_id)) => {
let enum_decl = parsed_decl_engine.get_enum(&decl_id);
for variant in enum_decl.variants.iter() {
let variant_name = &variant.name;
let variant_decl =
Declaration::EnumVariantDeclaration(EnumVariantDeclaration {
enum_ref: decl_id,
variant_name: variant_name.clone(),
variant_decl_span: variant.span.clone(),
});
self.module
.lookup_submodule_mut(handler, engines, dst)?
.current_items_mut()
.insert_glob_use_symbol(
engines,
variant_name.clone(),
path.clone(),
&ResolvedDeclaration::Parsed(variant_decl),
visibility,
);
}
}
ResolvedDeclaration::Typed(TyDecl::EnumDecl(ty::EnumDecl { decl_id, .. })) => {
let enum_decl = decl_engine.get_enum(&decl_id);
let enum_ref = DeclRef::new(
enum_decl.call_path.suffix.clone(),
decl_id,
enum_decl.span(),
);
for variant_decl in enum_decl.variants.iter() {
let variant_name = &variant_decl.name;
let decl =
ResolvedDeclaration::Typed(TyDecl::EnumVariantDecl(ty::EnumVariantDecl {
enum_ref: enum_ref.clone(),
variant_name: variant_name.clone(),
variant_decl_span: variant_decl.span.clone(),
}));
self.module
.lookup_submodule_mut(handler, engines, dst)?
.current_items_mut()
.insert_glob_use_symbol(
engines,
variant_name.clone(),
path.clone(),
&decl,
visibility,
);
}
}
_ => {
return Err(handler.emit_err(CompileError::Internal(
"Attempting to import variants of something that isn't an enum",
enum_name.span(),
)));
}
};
Ok(())
}
fn check_module_privacy(
&self,
handler: &Handler,
engines: &Engines,
src: &ModulePath,
) -> Result<(), ErrorEmitted> {
let dst = self.module.mod_path();
if !is_ancestor(src, dst) {
for prefix in iter_prefixes(src).skip(1) {
let module = self.module.lookup_submodule(handler, engines, prefix)?;
if module.visibility().is_private() {
let prefix_last = prefix[prefix.len() - 1].clone();
handler.emit_err(CompileError::ImportPrivateModule {
span: prefix_last.span(),
name: prefix_last,
});
}
}
}
Ok(())
}
pub(crate) fn resolve_call_path(
&self,
handler: &Handler,
engines: &Engines,
mod_path: &ModulePath,
call_path: &CallPath,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
let (decl, _) =
self.resolve_call_path_and_mod_path(handler, engines, mod_path, call_path, self_type)?;
Ok(decl)
}
pub(crate) fn resolve_call_path_and_mod_path(
&self,
handler: &Handler,
engines: &Engines,
mod_path: &ModulePath,
call_path: &CallPath,
self_type: Option<TypeId>,
) -> Result<(ResolvedDeclaration, Vec<Ident>), ErrorEmitted> {
let symbol_path: Vec<_> = mod_path
.iter()
.chain(&call_path.prefixes)
.cloned()
.collect();
self.resolve_symbol_and_mod_path(
handler,
engines,
&symbol_path,
&call_path.suffix,
self_type,
)
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn resolve_call_path_and_root_type_id(
&self,
handler: &Handler,
engines: &Engines,
module: &Module,
root_type_id: TypeId,
mut as_trait: Option<CallPath>,
call_path: &CallPath,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
let mut decl_opt = None;
let mut type_id_opt = Some(root_type_id);
for ident in call_path.prefixes.iter() {
if let Some(type_id) = type_id_opt {
type_id_opt = None;
decl_opt = Some(self.resolve_associated_type_from_type_id(
handler,
engines,
module,
ident,
type_id,
as_trait.clone(),
self_type,
)?);
as_trait = None;
} else if let Some(decl) = decl_opt {
decl_opt = Some(self.resolve_associated_type(
handler,
engines,
module,
ident,
decl,
as_trait.clone(),
self_type,
)?);
as_trait = None;
}
}
if let Some(type_id) = type_id_opt {
let decl = self.resolve_associated_type_from_type_id(
handler,
engines,
module,
&call_path.suffix,
type_id,
as_trait,
self_type,
)?;
return Ok(decl);
}
if let Some(decl) = decl_opt {
let decl = self.resolve_associated_item(
handler,
engines,
module,
&call_path.suffix,
decl,
as_trait,
self_type,
)?;
Ok(decl)
} else {
Err(handler.emit_err(CompileError::Internal("Unexpected error", call_path.span())))
}
}
pub(crate) fn resolve_symbol(
&self,
handler: &Handler,
engines: &Engines,
mod_path: &ModulePath,
symbol: &Ident,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
let (decl, _) =
self.resolve_symbol_and_mod_path(handler, engines, mod_path, symbol, self_type)?;
Ok(decl)
}
fn resolve_symbol_and_mod_path(
&self,
handler: &Handler,
engines: &Engines,
mod_path: &ModulePath,
symbol: &Ident,
self_type: Option<TypeId>,
) -> Result<(ResolvedDeclaration, Vec<Ident>), ErrorEmitted> {
let mut module = &self.module;
let mut current_mod_path = vec![];
let mut decl_opt = None;
for ident in mod_path.iter() {
if let Some(decl) = decl_opt {
decl_opt = Some(self.resolve_associated_type(
handler, engines, module, ident, decl, None, self_type,
)?);
} else {
match module.submodules.get(ident.as_str()) {
Some(ns) => {
module = ns;
current_mod_path.push(ident.clone());
}
None => {
decl_opt =
Some(self.resolve_symbol_helper(handler, engines, ident, module)?);
}
}
}
}
if let Some(decl) = decl_opt {
let decl = self
.resolve_associated_item(handler, engines, module, symbol, decl, None, self_type)?;
return Ok((decl, current_mod_path));
}
self.module
.lookup_submodule(handler, engines, mod_path)
.and_then(|module| {
let decl = self.resolve_symbol_helper(handler, engines, symbol, module)?;
Ok((decl, mod_path.to_vec()))
})
}
#[allow(clippy::too_many_arguments)]
fn resolve_associated_type(
&self,
handler: &Handler,
engines: &Engines,
module: &Module,
symbol: &Ident,
decl: ResolvedDeclaration,
as_trait: Option<CallPath>,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
let type_info = self.decl_to_type_info(handler, engines, symbol, decl)?;
let type_id = engines
.te()
.insert(engines, type_info, symbol.span().source_id());
self.resolve_associated_type_from_type_id(
handler, engines, module, symbol, type_id, as_trait, self_type,
)
}
#[allow(clippy::too_many_arguments)]
fn resolve_associated_item(
&self,
handler: &Handler,
engines: &Engines,
module: &Module,
symbol: &Ident,
decl: ResolvedDeclaration,
as_trait: Option<CallPath>,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
let type_info = self.decl_to_type_info(handler, engines, symbol, decl)?;
let type_id = engines
.te()
.insert(engines, type_info, symbol.span().source_id());
self.resolve_associated_item_from_type_id(
handler, engines, module, symbol, type_id, as_trait, self_type,
)
}
fn decl_to_type_info(
&self,
handler: &Handler,
engines: &Engines,
symbol: &Ident,
decl: ResolvedDeclaration,
) -> Result<TypeInfo, ErrorEmitted> {
match decl {
ResolvedDeclaration::Parsed(_decl) => todo!(),
ResolvedDeclaration::Typed(decl) => Ok(match decl.clone() {
ty::TyDecl::StructDecl(struct_ty_decl) => TypeInfo::Struct(struct_ty_decl.decl_id),
ty::TyDecl::EnumDecl(enum_ty_decl) => TypeInfo::Enum(enum_ty_decl.decl_id),
ty::TyDecl::TraitTypeDecl(type_decl) => {
let type_decl = engines.de().get_type(&type_decl.decl_id);
if type_decl.ty.is_none() {
return Err(handler.emit_err(CompileError::Internal(
"Trait type declaration has no type",
symbol.span(),
)));
}
(*engines.te().get(type_decl.ty.clone().unwrap().type_id)).clone()
}
_ => {
return Err(handler.emit_err(CompileError::SymbolNotFound {
name: symbol.clone(),
span: symbol.span(),
}))
}
}),
}
}
#[allow(clippy::too_many_arguments)]
fn resolve_associated_type_from_type_id(
&self,
handler: &Handler,
engines: &Engines,
module: &Module,
symbol: &Ident,
type_id: TypeId,
as_trait: Option<CallPath>,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
let item_decl = self.resolve_associated_item_from_type_id(
handler, engines, module, symbol, type_id, as_trait, self_type,
)?;
Ok(item_decl)
}
#[allow(clippy::too_many_arguments)]
fn resolve_associated_item_from_type_id(
&self,
handler: &Handler,
engines: &Engines,
module: &Module,
symbol: &Ident,
type_id: TypeId,
as_trait: Option<CallPath>,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
let type_id = if engines.te().get(type_id).is_self_type() {
if let Some(self_type) = self_type {
self_type
} else {
return Err(handler.emit_err(CompileError::Internal(
"Self type not provided.",
symbol.span(),
)));
}
} else {
type_id
};
let item_ref = module
.current_items()
.implemented_traits
.get_trait_item_for_type(handler, engines, symbol, type_id, as_trait)?;
match item_ref {
ResolvedTraitImplItem::Parsed(_item) => todo!(),
ResolvedTraitImplItem::Typed(item) => match item {
TyTraitItem::Fn(fn_ref) => Ok(ResolvedDeclaration::Typed(fn_ref.into())),
TyTraitItem::Constant(const_ref) => {
Ok(ResolvedDeclaration::Typed(const_ref.into()))
}
TyTraitItem::Type(type_ref) => Ok(ResolvedDeclaration::Typed(type_ref.into())),
},
}
}
fn resolve_symbol_helper(
&self,
handler: &Handler,
engines: &Engines,
symbol: &Ident,
module: &Module,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
if let Some(decl) = module.current_items().symbols.get(symbol) {
return Ok(decl.clone());
}
if let Some((_, _, decl, _)) = module.current_items().use_item_synonyms.get(symbol) {
return Ok(decl.clone());
}
if let Some(decls) = module.current_items().use_glob_synonyms.get(symbol) {
if decls.len() == 1 {
return Ok(decls[0].1.clone());
} else if decls.is_empty() {
return Err(handler.emit_err(CompileError::Internal(
"The name {symbol} was bound in a star import, but no corresponding module paths were found",
symbol.span(),
)));
} else {
return Err(handler.emit_err(CompileError::SymbolWithMultipleBindings {
name: symbol.clone(),
paths: decls
.iter()
.map(|(path, decl, _)| {
let mut path_strs =
path.iter().map(|x| x.to_string()).collect::<Vec<_>>();
match decl {
ResolvedDeclaration::Parsed(decl) => {
if let Declaration::EnumVariantDeclaration(decl) = decl {
let enum_ref = engines.pe().get_enum(&decl.enum_ref);
path_strs.push(enum_ref.name().to_string())
};
}
ResolvedDeclaration::Typed(decl) => {
if let TyDecl::EnumVariantDecl(ty::EnumVariantDecl {
enum_ref,
..
}) = decl
{
path_strs.push(enum_ref.name().to_string())
};
}
}
path_strs.join("::")
})
.collect(),
span: symbol.span(),
}));
}
}
Err(handler.emit_err(CompileError::SymbolNotFound {
name: symbol.clone(),
span: symbol.span(),
}))
}
}
impl From<Module> for Root {
fn from(module: Module) -> Self {
Root { module }
}
}
impl From<Namespace> for Root {
fn from(namespace: Namespace) -> Self {
namespace.root
}
}
fn is_ancestor(src: &ModulePath, dst: &ModulePath) -> bool {
dst.len() >= src.len() && src.iter().zip(dst).all(|(src, dst)| src == dst)
}