//! Definition of `SolverDefId`

use hir_def::{
    AdtId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, EnumId,
    EnumVariantId, ExpressionStoreOwnerId, FunctionId, GenericDefId, ImplId, StaticId, StructId,
    TraitId, TypeAliasId, UnionId, VariantId,
    signatures::{
        ConstSignature, EnumSignature, FunctionSignature, StaticSignature, StructSignature,
        TraitSignature, TypeAliasSignature, UnionSignature,
    },
};
use rustc_type_ir::inherent;
use salsa::SalsaValue;
use stdx::impl_from;

use crate::{
    InferBodyId,
    db::{
        AnonConstId, GeneralConstId, InternedClosureId, InternedCoroutineClosureId,
        InternedCoroutineId, InternedOpaqueTyId,
    },
};

use super::DbInterner;

#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Ctor {
    Struct(StructId),
    Enum(EnumVariantId),
}

#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, SalsaValue)]
pub enum SolverDefId<'db> {
    AdtId(AdtId),
    ConstId(ConstId),
    FunctionId(FunctionId),
    ImplId(ImplId),
    BuiltinDeriveImplId(BuiltinDeriveImplId),
    StaticId(StaticId),
    AnonConstId(AnonConstId<'db>),
    TraitId(TraitId),
    TypeAliasId(TypeAliasId),
    InternedClosureId(InternedClosureId<'db>),
    InternedCoroutineId(InternedCoroutineId<'db>),
    InternedCoroutineClosureId(InternedCoroutineClosureId<'db>),
    InternedOpaqueTyId(InternedOpaqueTyId<'db>),
    EnumVariantId(EnumVariantId),
    Ctor(Ctor),
}

impl std::fmt::Debug for SolverDefId<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let interner = DbInterner::conjure();
        let db = interner.db;
        match *self {
            SolverDefId::AdtId(AdtId::StructId(id)) => {
                f.debug_tuple("AdtId").field(&StructSignature::of(db, id).name.as_str()).finish()
            }
            SolverDefId::AdtId(AdtId::EnumId(id)) => {
                f.debug_tuple("AdtId").field(&EnumSignature::of(db, id).name.as_str()).finish()
            }
            SolverDefId::AdtId(AdtId::UnionId(id)) => {
                f.debug_tuple("AdtId").field(&UnionSignature::of(db, id).name.as_str()).finish()
            }
            SolverDefId::ConstId(id) => f
                .debug_tuple("ConstId")
                .field(&ConstSignature::of(db, id).name.as_ref().map_or("_", |name| name.as_str()))
                .finish(),
            SolverDefId::FunctionId(id) => f
                .debug_tuple("FunctionId")
                .field(&FunctionSignature::of(db, id).name.as_str())
                .finish(),
            SolverDefId::ImplId(id) => f.debug_tuple("ImplId").field(&id).finish(),
            SolverDefId::BuiltinDeriveImplId(id) => f.debug_tuple("ImplId").field(&id).finish(),
            SolverDefId::StaticId(id) => {
                f.debug_tuple("StaticId").field(&StaticSignature::of(db, id).name.as_str()).finish()
            }
            SolverDefId::TraitId(id) => {
                f.debug_tuple("TraitId").field(&TraitSignature::of(db, id).name.as_str()).finish()
            }
            SolverDefId::TypeAliasId(id) => f
                .debug_tuple("TypeAliasId")
                .field(&TypeAliasSignature::of(db, id).name.as_str())
                .finish(),
            SolverDefId::InternedClosureId(id) => {
                f.debug_tuple("InternedClosureId").field(&id).finish()
            }
            SolverDefId::InternedCoroutineId(id) => {
                f.debug_tuple("InternedCoroutineId").field(&id).finish()
            }
            SolverDefId::InternedCoroutineClosureId(id) => {
                f.debug_tuple("InternedCoroutineClosureId").field(&id).finish()
            }
            SolverDefId::InternedOpaqueTyId(id) => {
                f.debug_tuple("InternedOpaqueTyId").field(&id).finish()
            }
            SolverDefId::EnumVariantId(id) => {
                let parent_enum = id.loc(db).parent;
                f.debug_tuple("EnumVariantId")
                    .field(&format_args!(
                        "\"{}::{}\"",
                        EnumSignature::of(db, parent_enum).name.as_str(),
                        parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str()
                    ))
                    .finish()
            }
            SolverDefId::AnonConstId(id) => f.debug_tuple("AnonConstId").field(&id).finish(),
            SolverDefId::Ctor(Ctor::Struct(id)) => {
                f.debug_tuple("Ctor").field(&StructSignature::of(db, id).name.as_str()).finish()
            }
            SolverDefId::Ctor(Ctor::Enum(id)) => {
                let parent_enum = id.loc(db).parent;
                f.debug_tuple("Ctor")
                    .field(&format_args!(
                        "\"{}::{}\"",
                        EnumSignature::of(db, parent_enum).name.as_str(),
                        parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str()
                    ))
                    .finish()
            }
        }
    }
}

impl_from!(
    impl<'db>
    AdtId(StructId, EnumId, UnionId),
    ConstId,
    FunctionId,
    ImplId,
    BuiltinDeriveImplId,
    StaticId,
    AnonConstId<'db>,
    TraitId,
    TypeAliasId,
    InternedClosureId<'db>,
    InternedCoroutineId<'db>,
    InternedCoroutineClosureId<'db>,
    InternedOpaqueTyId<'db>,
    EnumVariantId,
    Ctor
    for SolverDefId<'db>
);

impl_from!(
    impl<'db>
    GenericDefId { AdtId, ConstId, FunctionId, ImplId, StaticId, TraitId, TypeAliasId }
    for SolverDefId<'db>
);

impl<'db> From<GeneralConstId<'db>> for SolverDefId<'db> {
    #[inline]
    fn from(value: GeneralConstId<'db>) -> Self {
        match value {
            GeneralConstId::ConstId(const_id) => SolverDefId::ConstId(const_id),
            GeneralConstId::StaticId(static_id) => SolverDefId::StaticId(static_id),
            GeneralConstId::AnonConstId(anon_const_id) => SolverDefId::AnonConstId(anon_const_id),
        }
    }
}

impl<'db> From<CallableDefId> for SolverDefId<'db> {
    #[inline]
    fn from(value: CallableDefId) -> Self {
        match value {
            CallableDefId::FunctionId(id) => id.into(),
            CallableDefId::StructId(id) => id.into(),
            CallableDefId::EnumVariantId(id) => id.into(),
        }
    }
}

impl<'db> From<DefWithBodyId> for SolverDefId<'db> {
    #[inline]
    fn from(value: DefWithBodyId) -> Self {
        match value {
            DefWithBodyId::FunctionId(id) => id.into(),
            DefWithBodyId::StaticId(id) => id.into(),
            DefWithBodyId::ConstId(id) => id.into(),
            DefWithBodyId::VariantId(id) => id.into(),
        }
    }
}

impl<'db> From<InferBodyId<'db>> for SolverDefId<'db> {
    #[inline]
    fn from(value: InferBodyId<'db>) -> Self {
        match value {
            InferBodyId::DefWithBodyId(id) => id.into(),
            InferBodyId::AnonConstId(id) => id.into(),
        }
    }
}

impl<'db> From<VariantId> for SolverDefId<'db> {
    #[inline]
    fn from(value: VariantId) -> Self {
        match value {
            VariantId::EnumVariantId(id) => id.into(),
            VariantId::StructId(id) => id.into(),
            VariantId::UnionId(id) => id.into(),
        }
    }
}

impl<'db> From<ExpressionStoreOwnerId> for SolverDefId<'db> {
    #[inline]
    fn from(value: ExpressionStoreOwnerId) -> Self {
        match value {
            ExpressionStoreOwnerId::Body(body_id) => body_id.into(),
            ExpressionStoreOwnerId::Signature(sig_id) => sig_id.into(),
            ExpressionStoreOwnerId::VariantFields(variant_id) => variant_id.into(),
        }
    }
}

impl TryFrom<SolverDefId<'_>> for AttrDefId {
    type Error = ();
    #[inline]
    fn try_from(value: SolverDefId<'_>) -> Result<Self, Self::Error> {
        match value {
            SolverDefId::AdtId(it) => Ok(it.into()),
            SolverDefId::ConstId(it) => Ok(it.into()),
            SolverDefId::FunctionId(it) => Ok(it.into()),
            SolverDefId::ImplId(it) => Ok(it.into()),
            SolverDefId::StaticId(it) => Ok(it.into()),
            SolverDefId::TraitId(it) => Ok(it.into()),
            SolverDefId::TypeAliasId(it) => Ok(it.into()),
            SolverDefId::EnumVariantId(it) => Ok(it.into()),
            SolverDefId::Ctor(Ctor::Struct(it)) => Ok(it.into()),
            SolverDefId::Ctor(Ctor::Enum(it)) => Ok(it.into()),
            SolverDefId::BuiltinDeriveImplId(_)
            | SolverDefId::InternedClosureId(_)
            | SolverDefId::InternedCoroutineId(_)
            | SolverDefId::InternedCoroutineClosureId(_)
            | SolverDefId::InternedOpaqueTyId(_)
            | SolverDefId::AnonConstId(_) => Err(()),
        }
    }
}

impl TryFrom<SolverDefId<'_>> for DefWithBodyId {
    type Error = ();

    #[inline]
    fn try_from(value: SolverDefId<'_>) -> Result<Self, Self::Error> {
        let id = match value {
            SolverDefId::ConstId(id) => id.into(),
            SolverDefId::FunctionId(id) => id.into(),
            SolverDefId::StaticId(id) => id.into(),
            SolverDefId::EnumVariantId(id) | SolverDefId::Ctor(Ctor::Enum(id)) => id.into(),
            SolverDefId::InternedOpaqueTyId(_)
            | SolverDefId::TraitId(_)
            | SolverDefId::TypeAliasId(_)
            | SolverDefId::ImplId(_)
            | SolverDefId::BuiltinDeriveImplId(_)
            | SolverDefId::InternedClosureId(_)
            | SolverDefId::InternedCoroutineId(_)
            | SolverDefId::InternedCoroutineClosureId(_)
            | SolverDefId::Ctor(Ctor::Struct(_))
            | SolverDefId::AnonConstId(_)
            | SolverDefId::AdtId(_) => return Err(()),
        };
        Ok(id)
    }
}

impl<'db> TryFrom<SolverDefId<'db>> for InferBodyId<'db> {
    type Error = ();

    #[inline]
    fn try_from(value: SolverDefId<'db>) -> Result<Self, Self::Error> {
        let id = match value {
            SolverDefId::ConstId(id) => id.into(),
            SolverDefId::FunctionId(id) => id.into(),
            SolverDefId::StaticId(id) => id.into(),
            SolverDefId::EnumVariantId(id) | SolverDefId::Ctor(Ctor::Enum(id)) => id.into(),
            SolverDefId::AnonConstId(id) => id.into(),
            SolverDefId::InternedOpaqueTyId(_)
            | SolverDefId::TraitId(_)
            | SolverDefId::TypeAliasId(_)
            | SolverDefId::ImplId(_)
            | SolverDefId::BuiltinDeriveImplId(_)
            | SolverDefId::InternedClosureId(_)
            | SolverDefId::InternedCoroutineId(_)
            | SolverDefId::InternedCoroutineClosureId(_)
            | SolverDefId::Ctor(Ctor::Struct(_))
            | SolverDefId::AdtId(_) => return Err(()),
        };
        Ok(id)
    }
}

impl TryFrom<SolverDefId<'_>> for GenericDefId {
    type Error = ();

    fn try_from(value: SolverDefId<'_>) -> Result<Self, Self::Error> {
        Ok(match value {
            SolverDefId::AdtId(adt_id) => GenericDefId::AdtId(adt_id),
            SolverDefId::ConstId(const_id) => GenericDefId::ConstId(const_id),
            SolverDefId::FunctionId(function_id) => GenericDefId::FunctionId(function_id),
            SolverDefId::ImplId(impl_id) => GenericDefId::ImplId(impl_id),
            SolverDefId::StaticId(static_id) => GenericDefId::StaticId(static_id),
            SolverDefId::TraitId(trait_id) => GenericDefId::TraitId(trait_id),
            SolverDefId::TypeAliasId(type_alias_id) => GenericDefId::TypeAliasId(type_alias_id),
            SolverDefId::InternedClosureId(_)
            | SolverDefId::InternedCoroutineId(_)
            | SolverDefId::InternedCoroutineClosureId(_)
            | SolverDefId::InternedOpaqueTyId(_)
            | SolverDefId::EnumVariantId(_)
            | SolverDefId::BuiltinDeriveImplId(_)
            | SolverDefId::AnonConstId(_)
            | SolverDefId::Ctor(_) => return Err(()),
        })
    }
}

impl<'db> inherent::DefId<DbInterner<'db>> for SolverDefId<'db> {
    fn as_local(self) -> Option<SolverDefId<'db>> {
        Some(self)
    }
    fn is_local(self) -> bool {
        true
    }
}

macro_rules! declare_id_wrapper {
    ($name:ident, $wraps:ident) => {
        declare_id_wrapper!($name, $wraps, SolverDefId<'db>);
    };

    ($name:ident, $wraps:ident, $local:ty) => {
        declare_id_wrapper!($name, $wraps, $local, no_try_from);

        impl TryFrom<SolverDefId<'_>> for $name {
            type Error = ();

            #[inline]
            fn try_from(value: SolverDefId<'_>) -> Result<Self, Self::Error> {
                match value {
                    SolverDefId::$wraps(it) => Ok(Self(it)),
                    _ => Err(()),
                }
            }
        }
    };

    ($name:ident, $wraps:ident, $local:ty, no_try_from) => {
        #[derive(Clone, Copy, PartialEq, Eq, Hash)]
        pub struct $name(pub $wraps);

        impl std::fmt::Debug for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                std::fmt::Debug::fmt(&SolverDefId::from(self.0), f)
            }
        }

        impl From<$name> for $wraps {
            #[inline]
            fn from(value: $name) -> $wraps {
                value.0
            }
        }

        impl From<$wraps> for $name {
            #[inline]
            fn from(value: $wraps) -> $name {
                Self(value)
            }
        }

        impl<'db> From<$name> for SolverDefId<'db> {
            #[inline]
            fn from(value: $name) -> SolverDefId<'db> {
                value.0.into()
            }
        }

        impl<'db> inherent::DefId<DbInterner<'db>, $local> for $name {
            fn as_local(self) -> Option<$local> {
                Some(self.into())
            }
            fn is_local(self) -> bool {
                true
            }
        }
    };
}

/// This is similar to [`declare_id_wrapper`], but handles ids which have the `'db` lifetime.
macro_rules! declare_id_wrapper_with_lt {
    ($name:ident, $wraps:ident) => {
        declare_id_wrapper_with_lt!($name, $wraps, SolverDefId<'db>);
    };

    ($name:ident, $wraps:ident, $local:ty) => {
        declare_id_wrapper_with_lt!($name, $wraps, $local, no_try_from);

        impl<'db> TryFrom<SolverDefId<'db>> for $name<'db> {
            type Error = ();

            #[inline]
            fn try_from(value: SolverDefId<'db>) -> Result<Self, Self::Error> {
                match value {
                    SolverDefId::$wraps(it) => Ok(Self(it)),
                    _ => Err(()),
                }
            }
        }
    };

    ($name:ident, $wraps:ident, $local:ty, no_try_from) => {
        #[derive(Clone, Copy, PartialEq, Eq, Hash)]
        pub struct $name<'db>(pub $wraps<'db>);

        impl std::fmt::Debug for $name<'_> {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                std::fmt::Debug::fmt(&SolverDefId::from(self.0), f)
            }
        }

        impl<'db> From<$name<'db>> for $wraps<'db> {
            #[inline]
            fn from(value: $name<'db>) -> $wraps<'db> {
                value.0
            }
        }

        impl<'db> From<$wraps<'db>> for $name<'db> {
            #[inline]
            fn from(value: $wraps<'db>) -> $name<'db> {
                Self(value)
            }
        }

        impl<'db> From<$name<'db>> for SolverDefId<'db> {
            #[inline]
            fn from(value: $name<'db>) -> SolverDefId<'db> {
                value.0.into()
            }
        }

        impl<'db> inherent::DefId<DbInterner<'db>, $local> for $name<'db> {
            fn as_local(self) -> Option<$local> {
                Some(self.into())
            }
            fn is_local(self) -> bool {
                true
            }
        }
    };
}

declare_id_wrapper!(TraitIdWrapper, TraitId);
declare_id_wrapper!(TypeAliasIdWrapper, TypeAliasId);
declare_id_wrapper_with_lt!(ClosureIdWrapper, InternedClosureId);
declare_id_wrapper_with_lt!(CoroutineIdWrapper, InternedCoroutineId);
declare_id_wrapper_with_lt!(CoroutineClosureIdWrapper, InternedCoroutineClosureId);
declare_id_wrapper!(AdtIdWrapper, AdtId);
declare_id_wrapper_with_lt!(OpaqueTyIdWrapper, InternedOpaqueTyId, OpaqueTyIdWrapper<'db>);

macro_rules! declare_ty_const_pair {
    ( $ty_id_name:ident, $const_id_name:ident, $term_id_name:ident ) => {
        declare_id_wrapper!($ty_id_name, TypeAliasId);
        declare_id_wrapper!($const_id_name, ConstId);
        declare_id_wrapper!($term_id_name, TermId, SolverDefId<'db>, no_try_from);

        impl TryFrom<SolverDefId<'_>> for $term_id_name {
            type Error = ();

            #[inline]
            fn try_from(value: SolverDefId<'_>) -> Result<Self, Self::Error> {
                match value {
                    SolverDefId::TypeAliasId(it) => Ok(Self(TermId::TypeAliasId(it))),
                    SolverDefId::ConstId(it) => Ok(Self(TermId::ConstId(it))),
                    _ => Err(()),
                }
            }
        }

        impl From<$ty_id_name> for $term_id_name {
            fn from(value: $ty_id_name) -> Self {
                $term_id_name(TermId::TypeAliasId(value.0))
            }
        }

        impl From<$const_id_name> for $term_id_name {
            fn from(value: $const_id_name) -> Self {
                $term_id_name(TermId::ConstId(value.0))
            }
        }

        impl TryFrom<$term_id_name> for $ty_id_name {
            type Error = ();

            fn try_from(value: $term_id_name) -> Result<Self, Self::Error> {
                match value.0 {
                    TermId::TypeAliasId(id) => Ok($ty_id_name(id)),
                    TermId::ConstId(_) => Err(()),
                }
            }
        }

        impl TryFrom<$term_id_name> for $const_id_name {
            type Error = ();

            fn try_from(value: $term_id_name) -> Result<Self, Self::Error> {
                match value.0 {
                    TermId::ConstId(id) => Ok($const_id_name(id)),
                    TermId::TypeAliasId(_) => Err(()),
                }
            }
        }

        impl<'db> From<$const_id_name> for GeneralConstIdWrapper<'db> {
            fn from(value: $const_id_name) -> Self {
                GeneralConstIdWrapper(GeneralConstId::ConstId(value.0))
            }
        }
    };
}

declare_ty_const_pair!(TraitAssocTyId, TraitAssocConstId, TraitAssocTermId);
declare_ty_const_pair!(ImplOrTraitAssocTyId, ImplOrTraitAssocConstId, ImplOrTraitAssocTermId);
declare_ty_const_pair!(FreeTyAliasId, FreeConstAliasId, FreeTermAliasId);
declare_ty_const_pair!(InherentAssocTyId, InherentAssocConstId, InherentAssocTermId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum TermId {
    TypeAliasId(TypeAliasId),
    ConstId(ConstId),
}
impl_from!(TypeAliasId, ConstId for TermId);

impl<'db> From<TermId> for SolverDefId<'db> {
    fn from(value: TermId) -> Self {
        match value {
            TermId::TypeAliasId(id) => id.into(),
            TermId::ConstId(id) => id.into(),
        }
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct GeneralConstIdWrapper<'db>(pub GeneralConstId<'db>);

impl std::fmt::Debug for GeneralConstIdWrapper<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Debug::fmt(&self.0, f)
    }
}
impl<'db> From<GeneralConstIdWrapper<'db>> for GeneralConstId<'db> {
    #[inline]
    fn from(value: GeneralConstIdWrapper<'db>) -> GeneralConstId<'db> {
        value.0
    }
}
impl<'db> From<GeneralConstId<'db>> for GeneralConstIdWrapper<'db> {
    #[inline]
    fn from(value: GeneralConstId<'db>) -> GeneralConstIdWrapper<'db> {
        Self(value)
    }
}
impl<'db> From<GeneralConstIdWrapper<'db>> for SolverDefId<'db> {
    #[inline]
    fn from(value: GeneralConstIdWrapper<'db>) -> SolverDefId<'db> {
        match value.0 {
            GeneralConstId::ConstId(id) => SolverDefId::ConstId(id),
            GeneralConstId::StaticId(id) => SolverDefId::StaticId(id),
            GeneralConstId::AnonConstId(id) => SolverDefId::AnonConstId(id),
        }
    }
}
impl<'db> TryFrom<SolverDefId<'db>> for GeneralConstIdWrapper<'db> {
    type Error = ();
    #[inline]
    fn try_from(value: SolverDefId<'db>) -> Result<Self, Self::Error> {
        match value {
            SolverDefId::ConstId(it) => Ok(Self(it.into())),
            SolverDefId::StaticId(it) => Ok(Self(it.into())),
            SolverDefId::AnonConstId(it) => Ok(Self(it.into())),
            _ => Err(()),
        }
    }
}
impl<'db> inherent::DefId<DbInterner<'db>> for GeneralConstIdWrapper<'db> {
    fn as_local(self) -> Option<SolverDefId<'db>> {
        Some(self.into())
    }
    fn is_local(self) -> bool {
        true
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct CallableIdWrapper(pub CallableDefId);

impl std::fmt::Debug for CallableIdWrapper {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Debug::fmt(&self.0, f)
    }
}
impl From<CallableIdWrapper> for CallableDefId {
    #[inline]
    fn from(value: CallableIdWrapper) -> CallableDefId {
        value.0
    }
}
impl From<CallableDefId> for CallableIdWrapper {
    #[inline]
    fn from(value: CallableDefId) -> CallableIdWrapper {
        Self(value)
    }
}
impl<'db> From<CallableIdWrapper> for SolverDefId<'db> {
    #[inline]
    fn from(value: CallableIdWrapper) -> SolverDefId<'db> {
        match value.0 {
            CallableDefId::FunctionId(it) => it.into(),
            CallableDefId::StructId(it) => Ctor::Struct(it).into(),
            CallableDefId::EnumVariantId(it) => Ctor::Enum(it).into(),
        }
    }
}
impl TryFrom<SolverDefId<'_>> for CallableIdWrapper {
    type Error = ();
    #[inline]
    fn try_from(value: SolverDefId<'_>) -> Result<Self, Self::Error> {
        match value {
            SolverDefId::FunctionId(it) => Ok(Self(it.into())),
            SolverDefId::Ctor(Ctor::Struct(it)) => Ok(Self(it.into())),
            SolverDefId::Ctor(Ctor::Enum(it)) => Ok(Self(it.into())),
            _ => Err(()),
        }
    }
}
impl<'db> inherent::DefId<DbInterner<'db>> for CallableIdWrapper {
    fn as_local(self) -> Option<SolverDefId<'db>> {
        Some(self.into())
    }
    fn is_local(self) -> bool {
        true
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AnyImplId {
    ImplId(ImplId),
    BuiltinDeriveImplId(BuiltinDeriveImplId),
}

impl_from!(ImplId, BuiltinDeriveImplId for AnyImplId);

impl<'db> From<AnyImplId> for SolverDefId<'db> {
    #[inline]
    fn from(value: AnyImplId) -> SolverDefId<'db> {
        match value {
            AnyImplId::ImplId(it) => it.into(),
            AnyImplId::BuiltinDeriveImplId(it) => it.into(),
        }
    }
}
impl TryFrom<SolverDefId<'_>> for AnyImplId {
    type Error = ();
    #[inline]
    fn try_from(value: SolverDefId<'_>) -> Result<Self, Self::Error> {
        match value {
            SolverDefId::ImplId(it) => Ok(it.into()),
            SolverDefId::BuiltinDeriveImplId(it) => Ok(it.into()),
            _ => Err(()),
        }
    }
}
impl<'db> inherent::DefId<DbInterner<'db>> for AnyImplId {
    fn as_local(self) -> Option<SolverDefId<'db>> {
        Some(self.into())
    }
    fn is_local(self) -> bool {
        true
    }
}
