use std::hash::{Hash, Hasher};
use sway_error::handler::{ErrorEmitted, Handler};
use sway_types::{Ident, Named, Span, Spanned};
use crate::{
decl_engine::*,
engine_threading::*,
language::ty::{
self, TyAbiDecl, TyConstantDecl, TyDeclParsedType, TyEnumDecl, TyFunctionDecl,
TyImplSelfOrTrait, TyStorageDecl, TyStructDecl, TyTraitDecl, TyTraitFn, TyTraitType,
},
semantic_analysis::TypeCheckContext,
type_system::*,
};
pub type DeclRefFunction = DeclRef<DeclId<TyFunctionDecl>>;
pub type DeclRefTrait = DeclRef<DeclId<TyTraitDecl>>;
pub type DeclRefTraitFn = DeclRef<DeclId<TyTraitFn>>;
pub type DeclRefTraitType = DeclRef<DeclId<TyTraitType>>;
pub type DeclRefImplTrait = DeclRef<DeclId<TyImplSelfOrTrait>>;
pub type DeclRefStruct = DeclRef<DeclId<TyStructDecl>>;
pub type DeclRefStorage = DeclRef<DeclId<TyStorageDecl>>;
pub type DeclRefAbi = DeclRef<DeclId<TyAbiDecl>>;
pub type DeclRefConstant = DeclRef<DeclId<TyConstantDecl>>;
pub type DeclRefEnum = DeclRef<DeclId<TyEnumDecl>>;
pub type DeclRefMixedFunctional = DeclRef<AssociatedItemDeclId>;
pub type DeclRefMixedInterface = DeclRef<InterfaceDeclId>;
#[derive(Debug, Clone)]
pub struct DeclRef<I> {
name: Ident,
id: I,
decl_span: Span,
}
impl<I> DeclRef<I> {
pub(crate) fn new(name: Ident, id: I, decl_span: Span) -> Self {
DeclRef {
name,
id,
decl_span,
}
}
pub fn name(&self) -> &Ident {
&self.name
}
pub fn id(&self) -> &I {
&self.id
}
pub fn decl_span(&self) -> &Span {
&self.decl_span
}
}
impl<T> DeclRef<DeclId<T>> {
pub(crate) fn replace_id(&mut self, index: DeclId<T>) {
self.id.replace_id(index);
}
}
impl<T> DeclRef<DeclId<T>>
where
DeclEngine: DeclEngineIndex<T> + DeclEngineInsert<T> + DeclEngineGetParsedDeclId<T>,
T: Named + Spanned + IsConcrete + SubstTypes + Clone + TyDeclParsedType,
{
pub(crate) fn subst_types_and_insert_new(&self, ctx: &SubstTypesContext) -> Option<Self> {
let decl_engine = ctx.engines.de();
if ctx
.type_subst_map
.source_ids_contains_concrete_type(ctx.engines)
|| !decl_engine.get(&self.id).is_concrete(ctx.engines)
{
let mut decl = (*decl_engine.get(&self.id)).clone();
if decl.subst(ctx).has_changes() {
Some(decl_engine.insert(decl, decl_engine.get_parsed_decl_id(&self.id).as_ref()))
} else {
None
}
} else {
None
}
}
}
impl<T> DeclRef<DeclId<T>>
where
AssociatedItemDeclId: From<DeclId<T>>,
{
pub(crate) fn with_parent(
self,
decl_engine: &DeclEngine,
parent: AssociatedItemDeclId,
) -> Self {
let id: DeclId<T> = self.id;
decl_engine.register_parent(id.into(), parent);
self
}
}
impl<T> DeclRef<DeclId<T>>
where
AssociatedItemDeclId: From<DeclId<T>>,
DeclEngine: DeclEngineIndex<T> + DeclEngineInsert<T> + DeclEngineGetParsedDeclId<T>,
T: Named + Spanned + IsConcrete + SubstTypes + Clone + TyDeclParsedType,
{
pub(crate) fn subst_types_and_insert_new_with_parent(
&self,
ctx: &SubstTypesContext,
) -> Option<Self> {
let decl_engine = ctx.engines.de();
let mut decl = (*decl_engine.get(&self.id)).clone();
if decl.subst(ctx).has_changes() {
Some(
decl_engine
.insert(decl, decl_engine.get_parsed_decl_id(&self.id).as_ref())
.with_parent(decl_engine, self.id.into()),
)
} else {
None
}
}
}
impl<T> EqWithEngines for DeclRef<DeclId<T>>
where
DeclEngine: DeclEngineIndex<T>,
T: Named + Spanned + PartialEqWithEngines + EqWithEngines,
{
}
impl<T> PartialEqWithEngines for DeclRef<DeclId<T>>
where
DeclEngine: DeclEngineIndex<T>,
T: Named + Spanned + PartialEqWithEngines,
{
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
let decl_engine = ctx.engines().de();
let DeclRef {
name: ln,
id: lid,
decl_span: _,
} = self;
let DeclRef {
name: rn,
id: rid,
decl_span: _,
} = other;
ln == rn && decl_engine.get(lid).eq(&decl_engine.get(rid), ctx)
}
}
impl<T> HashWithEngines for DeclRef<DeclId<T>>
where
DeclEngine: DeclEngineIndex<T>,
T: Named + Spanned + HashWithEngines,
{
fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
let decl_engine = engines.de();
let DeclRef {
name,
id,
decl_span: _,
} = self;
name.hash(state);
decl_engine.get(id).hash(state, engines);
}
}
impl EqWithEngines for DeclRefMixedInterface {}
impl PartialEqWithEngines for DeclRefMixedInterface {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
let decl_engine = ctx.engines().de();
match (&self.id, &other.id) {
(InterfaceDeclId::Abi(self_id), InterfaceDeclId::Abi(other_id)) => {
let left = decl_engine.get(self_id);
let right = decl_engine.get(other_id);
self.name == other.name && left.eq(&right, ctx)
}
(InterfaceDeclId::Trait(self_id), InterfaceDeclId::Trait(other_id)) => {
let left = decl_engine.get(self_id);
let right = decl_engine.get(other_id);
self.name == other.name && left.eq(&right, ctx)
}
_ => false,
}
}
}
impl HashWithEngines for DeclRefMixedInterface {
fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
match self.id {
InterfaceDeclId::Abi(id) => {
state.write_u8(0);
let decl_engine = engines.de();
let decl = decl_engine.get(&id);
decl.hash(state, engines);
}
InterfaceDeclId::Trait(id) => {
state.write_u8(1);
let decl_engine = engines.de();
let decl = decl_engine.get(&id);
decl.hash(state, engines);
}
}
}
}
impl<I> Spanned for DeclRef<I> {
fn span(&self) -> Span {
self.decl_span.clone()
}
}
impl<T> SubstTypes for DeclRef<DeclId<T>>
where
DeclEngine: DeclEngineIndex<T>,
T: Named + Spanned + SubstTypes + Clone,
{
fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
let decl_engine = ctx.engines.de();
let mut decl = (*decl_engine.get(&self.id)).clone();
if decl.subst(ctx).has_changes() {
decl_engine.replace(self.id, decl);
HasChanges::Yes
} else {
HasChanges::No
}
}
}
impl ReplaceDecls for DeclRefFunction {
fn replace_decls_inner(
&mut self,
decl_mapping: &DeclMapping,
handler: &Handler,
ctx: &mut TypeCheckContext,
) -> Result<bool, ErrorEmitted> {
let engines = ctx.engines();
let decl_engine = engines.de();
let func = decl_engine.get(self);
if let Some(new_decl_ref) = decl_mapping.find_match(
handler,
ctx.engines(),
self.id.into(),
func.implementing_for_typeid,
ctx.self_type(),
)? {
return Ok(
if let AssociatedItemDeclId::Function(new_decl_ref) = new_decl_ref {
self.id = new_decl_ref;
true
} else {
false
},
);
}
let all_parents = decl_engine.find_all_parents(engines, &self.id);
for parent in all_parents.iter() {
if let Some(new_decl_ref) = decl_mapping.find_match(
handler,
ctx.engines(),
parent.clone(),
func.implementing_for_typeid,
ctx.self_type(),
)? {
return Ok(
if let AssociatedItemDeclId::Function(new_decl_ref) = new_decl_ref {
self.id = new_decl_ref;
true
} else {
false
},
);
}
}
Ok(false)
}
}
impl ReplaceFunctionImplementingType for DeclRefFunction {
fn replace_implementing_type(&mut self, engines: &Engines, implementing_type: ty::TyDecl) {
let decl_engine = engines.de();
let mut decl = (*decl_engine.get(&self.id)).clone();
decl.set_implementing_type(implementing_type);
decl_engine.replace(self.id, decl);
}
}