Migrate variance to the new solver
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index 3d06b52..a6b859b 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -1,55 +1,9 @@
 //! The implementation of `RustIrDatabase` for Chalk, which provides information
 //! about the code that Chalk needs.
-use hir_def::{CallableDefId, GenericDefId};
 
-use crate::{Interner, db::HirDatabase, mapping::from_chalk};
+use crate::Interner;
 
 pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
 pub(crate) type TraitId = chalk_ir::TraitId<Interner>;
 pub(crate) type AdtId = chalk_ir::AdtId<Interner>;
 pub(crate) type ImplId = chalk_ir::ImplId<Interner>;
-pub(crate) type Variances = chalk_ir::Variances<Interner>;
-
-impl chalk_ir::UnificationDatabase<Interner> for &dyn HirDatabase {
-    fn fn_def_variance(
-        &self,
-        fn_def_id: chalk_ir::FnDefId<Interner>,
-    ) -> chalk_ir::Variances<Interner> {
-        HirDatabase::fn_def_variance(*self, from_chalk(*self, fn_def_id))
-    }
-
-    fn adt_variance(&self, adt_id: chalk_ir::AdtId<Interner>) -> chalk_ir::Variances<Interner> {
-        HirDatabase::adt_variance(*self, adt_id.0)
-    }
-}
-
-pub(crate) fn fn_def_variance_query(
-    db: &dyn HirDatabase,
-    callable_def: CallableDefId,
-) -> Variances {
-    Variances::from_iter(
-        Interner,
-        db.variances_of(GenericDefId::from_callable(db, callable_def))
-            .as_deref()
-            .unwrap_or_default()
-            .iter()
-            .map(|v| match v {
-                crate::variance::Variance::Covariant => chalk_ir::Variance::Covariant,
-                crate::variance::Variance::Invariant => chalk_ir::Variance::Invariant,
-                crate::variance::Variance::Contravariant => chalk_ir::Variance::Contravariant,
-                crate::variance::Variance::Bivariant => chalk_ir::Variance::Invariant,
-            }),
-    )
-}
-
-pub(crate) fn adt_variance_query(db: &dyn HirDatabase, adt_id: hir_def::AdtId) -> Variances {
-    Variances::from_iter(
-        Interner,
-        db.variances_of(adt_id.into()).as_deref().unwrap_or_default().iter().map(|v| match v {
-            crate::variance::Variance::Covariant => chalk_ir::Variance::Covariant,
-            crate::variance::Variance::Invariant => chalk_ir::Variance::Invariant,
-            crate::variance::Variance::Contravariant => chalk_ir::Variance::Contravariant,
-            crate::variance::Variance::Bivariant => chalk_ir::Variance::Invariant,
-        }),
-    )
-}
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index a315f69..4ea563d 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -3,8 +3,8 @@
 use hir_def::{ItemContainerId, Lookup, TraitId};
 
 use crate::{
-    Binders, DynTy, Interner, ProjectionTy, Substitution, TraitRef, Ty, db::HirDatabase,
-    from_assoc_type_id, from_chalk_trait_id, generics::generics, to_chalk_trait_id,
+    Interner, ProjectionTy, Substitution, TraitRef, Ty, db::HirDatabase, from_assoc_type_id,
+    from_chalk_trait_id, generics::generics, to_chalk_trait_id,
 };
 
 pub(crate) trait ProjectionTyExt {
@@ -35,23 +35,6 @@
     }
 }
 
-pub(crate) trait DynTyExt {
-    fn principal(&self) -> Option<Binders<Binders<&TraitRef>>>;
-}
-
-impl DynTyExt for DynTy {
-    fn principal(&self) -> Option<Binders<Binders<&TraitRef>>> {
-        self.bounds.as_ref().filter_map(|bounds| {
-            bounds.interned().first().and_then(|b| {
-                b.as_ref().filter_map(|b| match b {
-                    crate::WhereClause::Implemented(trait_ref) => Some(trait_ref),
-                    _ => None,
-                })
-            })
-        })
-    }
-}
-
 pub(crate) trait TraitRefExt {
     fn hir_trait_id(&self) -> TraitId;
 }
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 7ad76f3..a4c19ee 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -17,7 +17,6 @@
 
 use crate::{
     Binders, ImplTraitId, ImplTraits, InferenceResult, TraitEnvironment, Ty, TyDefId, ValueTyDefId,
-    chalk_db,
     consteval::ConstEvalError,
     dyn_compatibility::DynCompatibilityViolation,
     layout::{Layout, LayoutError},
@@ -308,19 +307,13 @@
     #[salsa::interned]
     fn intern_coroutine(&self, id: InternedCoroutine) -> InternedCoroutineId;
 
-    #[salsa::invoke(chalk_db::fn_def_variance_query)]
-    fn fn_def_variance(&self, fn_def_id: CallableDefId) -> chalk_db::Variances;
-
-    #[salsa::invoke(chalk_db::adt_variance_query)]
-    fn adt_variance(&self, adt_id: AdtId) -> chalk_db::Variances;
-
     #[salsa::invoke(crate::variance::variances_of)]
     #[salsa::cycle(
         // cycle_fn = crate::variance::variances_of_cycle_fn,
         // cycle_initial = crate::variance::variances_of_cycle_initial,
         cycle_result = crate::variance::variances_of_cycle_initial,
     )]
-    fn variances_of(&self, def: GenericDefId) -> Option<Arc<[crate::variance::Variance]>>;
+    fn variances_of(&self, def: GenericDefId) -> crate::next_solver::VariancesOf<'_>;
 
     // next trait solver
 
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 7277617..7758517 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -117,7 +117,6 @@
     TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits,
     is_fn_unsafe_to_call, target_feature_is_safe_in_target,
 };
-pub use variance::Variance;
 
 use chalk_ir::{BoundVar, DebruijnIndex, Safety, Scalar};
 
diff --git a/crates/hir-ty/src/next_solver/def_id.rs b/crates/hir-ty/src/next_solver/def_id.rs
index 8525d4b..928e132 100644
--- a/crates/hir-ty/src/next_solver/def_id.rs
+++ b/crates/hir-ty/src/next_solver/def_id.rs
@@ -155,7 +155,7 @@
 }
 
 impl TryFrom<SolverDefId> for GenericDefId {
-    type Error = SolverDefId;
+    type Error = ();
 
     fn try_from(value: SolverDefId) -> Result<Self, Self::Error> {
         Ok(match value {
@@ -170,7 +170,7 @@
             | SolverDefId::InternedCoroutineId(_)
             | SolverDefId::InternedOpaqueTyId(_)
             | SolverDefId::EnumVariantId(_)
-            | SolverDefId::Ctor(_) => return Err(value),
+            | SolverDefId::Ctor(_) => return Err(()),
         })
     }
 }
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index cfa8b5b..7be8911 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -83,7 +83,7 @@
     ($name:ident, $ty:ty) => {
         interned_vec_nolifetime_salsa!($name, $ty, nofold);
 
-        impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name {
+        impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name<'db> {
             fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
                 self,
                 folder: &mut F,
@@ -104,7 +104,7 @@
             }
         }
 
-        impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name {
+        impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name<'db> {
             fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
                 &self,
                 visitor: &mut V,
@@ -117,14 +117,14 @@
         }
     };
     ($name:ident, $ty:ty, nofold) => {
-        #[salsa::interned(no_lifetime, constructor = new_, debug)]
+        #[salsa::interned(constructor = new_, debug)]
         pub struct $name {
             #[returns(ref)]
             inner_: smallvec::SmallVec<[$ty; 2]>,
         }
 
-        impl $name {
-            pub fn new_from_iter<'db>(
+        impl<'db> $name<'db> {
+            pub fn new_from_iter(
                 interner: DbInterner<'db>,
                 data: impl IntoIterator<Item = $ty>,
             ) -> Self {
@@ -140,7 +140,7 @@
             }
         }
 
-        impl rustc_type_ir::inherent::SliceLike for $name {
+        impl<'db> rustc_type_ir::inherent::SliceLike for $name<'db> {
             type Item = $ty;
 
             type IntoIter = <smallvec::SmallVec<[$ty; 2]> as IntoIterator>::IntoIter;
@@ -154,7 +154,7 @@
             }
         }
 
-        impl IntoIterator for $name {
+        impl<'db> IntoIterator for $name<'db> {
             type Item = $ty;
             type IntoIter = <Self as rustc_type_ir::inherent::SliceLike>::IntoIter;
 
@@ -163,7 +163,7 @@
             }
         }
 
-        impl Default for $name {
+        impl<'db> Default for $name<'db> {
             fn default() -> Self {
                 $name::new_from_iter(DbInterner::conjure(), [])
             }
@@ -887,7 +887,7 @@
 impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
     type DefId = SolverDefId;
     type LocalDefId = SolverDefId;
-    type LocalDefIds = SolverDefIds;
+    type LocalDefIds = SolverDefIds<'db>;
     type TraitId = TraitIdWrapper;
     type ForeignId = TypeAliasIdWrapper;
     type FunctionId = CallableIdWrapper;
@@ -904,7 +904,7 @@
 
     type Term = Term<'db>;
 
-    type BoundVarKinds = BoundVarKinds;
+    type BoundVarKinds = BoundVarKinds<'db>;
     type BoundVarKind = BoundVarKind;
 
     type PredefinedOpaques = PredefinedOpaques<'db>;
@@ -977,7 +977,7 @@
 
     type GenericsOf = Generics;
 
-    type VariancesOf = VariancesOf;
+    type VariancesOf = VariancesOf<'db>;
 
     type AdtDef = AdtDef;
 
@@ -1045,10 +1045,9 @@
 
     fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
         let generic_def = match def_id {
-            SolverDefId::FunctionId(def_id) => def_id.into(),
-            SolverDefId::AdtId(def_id) => def_id.into(),
-            SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(),
-            SolverDefId::Ctor(Ctor::Enum(def_id)) => def_id.loc(self.db).parent.into(),
+            SolverDefId::Ctor(Ctor::Enum(def_id)) | SolverDefId::EnumVariantId(def_id) => {
+                def_id.loc(self.db).parent.into()
+            }
             SolverDefId::InternedOpaqueTyId(_def_id) => {
                 // FIXME(next-solver): track variances
                 //
@@ -1059,17 +1058,20 @@
                     (0..self.generics_of(def_id).count()).map(|_| Variance::Invariant),
                 );
             }
-            _ => return VariancesOf::new_from_iter(self, []),
+            SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(),
+            SolverDefId::AdtId(def_id) => def_id.into(),
+            SolverDefId::FunctionId(def_id) => def_id.into(),
+            SolverDefId::ConstId(_)
+            | SolverDefId::StaticId(_)
+            | SolverDefId::TraitId(_)
+            | SolverDefId::TypeAliasId(_)
+            | SolverDefId::ImplId(_)
+            | SolverDefId::InternedClosureId(_)
+            | SolverDefId::InternedCoroutineId(_) => {
+                return VariancesOf::new_from_iter(self, []);
+            }
         };
-        VariancesOf::new_from_iter(
-            self,
-            self.db()
-                .variances_of(generic_def)
-                .as_deref()
-                .unwrap_or_default()
-                .iter()
-                .map(|v| v.to_nextsolver(self)),
-        )
+        self.db.variances_of(generic_def)
     }
 
     fn type_of(self, def_id: Self::DefId) -> EarlyBinder<Self, Self::Ty> {
diff --git a/crates/hir-ty/src/next_solver/mapping.rs b/crates/hir-ty/src/next_solver/mapping.rs
index 1a5982c..adbc609 100644
--- a/crates/hir-ty/src/next_solver/mapping.rs
+++ b/crates/hir-ty/src/next_solver/mapping.rs
@@ -605,8 +605,8 @@
     }
 }
 
-impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKinds {
+impl<'db> ChalkToNextSolver<'db, BoundVarKinds<'db>> for chalk_ir::VariableKinds<Interner> {
+    fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKinds<'db> {
         BoundVarKinds::new_from_iter(
             interner,
             self.iter(Interner).map(|v| v.to_nextsolver(interner)),
@@ -614,7 +614,7 @@
     }
 }
 
-impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKinds<Interner>> for BoundVarKinds {
+impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKinds<Interner>> for BoundVarKinds<'db> {
     fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKinds<Interner> {
         chalk_ir::VariableKinds::from_iter(Interner, self.iter().map(|v| v.to_chalk(interner)))
     }
@@ -763,36 +763,6 @@
     }
 }
 
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance {
-        match self {
-            crate::Variance::Covariant => rustc_type_ir::Variance::Covariant,
-            crate::Variance::Invariant => rustc_type_ir::Variance::Invariant,
-            crate::Variance::Contravariant => rustc_type_ir::Variance::Contravariant,
-            crate::Variance::Bivariant => rustc_type_ir::Variance::Bivariant,
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for chalk_ir::Variance {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance {
-        match self {
-            chalk_ir::Variance::Covariant => rustc_type_ir::Variance::Covariant,
-            chalk_ir::Variance::Invariant => rustc_type_ir::Variance::Invariant,
-            chalk_ir::Variance::Contravariant => rustc_type_ir::Variance::Contravariant,
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, VariancesOf> for chalk_ir::Variances<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> VariancesOf {
-        VariancesOf::new_from_iter(
-            interner,
-            self.as_slice(Interner).iter().map(|v| v.to_nextsolver(interner)),
-        )
-    }
-}
-
 impl<'db> ChalkToNextSolver<'db, Goal<DbInterner<'db>, Predicate<'db>>>
     for chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>
 {
diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs
index 0ff1101..46898dd 100644
--- a/crates/hir-ty/src/variance.rs
+++ b/crates/hir-ty/src/variance.rs
@@ -13,43 +13,45 @@
 //! by the next salsa version. If not, we will likely have to adapt and go with the rustc approach
 //! while installing firewall per item queries to prevent invalidation issues.
 
-use crate::db::HirDatabase;
-use crate::generics::{Generics, generics};
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk};
-use crate::{
-    AliasTy, Const, ConstScalar, DynTyExt, GenericArg, GenericArgData, Interner, Lifetime,
-    LifetimeData, Ty, TyKind,
+use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId, signatures::StructFlags};
+use rustc_ast_ir::Mutability;
+use rustc_type_ir::{
+    Variance,
+    inherent::{AdtDef, IntoKind, SliceLike},
 };
-use chalk_ir::Mutability;
-use hir_def::signatures::StructFlags;
-use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId};
-use std::fmt;
-use std::ops::Not;
 use stdx::never;
-use triomphe::Arc;
 
-pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Arc<[Variance]>> {
+use crate::{
+    db::HirDatabase,
+    generics::{Generics, generics},
+    next_solver::{
+        Const, ConstKind, DbInterner, ExistentialPredicate, GenericArg, GenericArgs, Region,
+        RegionKind, Term, Ty, TyKind, VariancesOf,
+    },
+};
+
+pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> VariancesOf<'_> {
     tracing::debug!("variances_of(def={:?})", def);
+    let interner = DbInterner::new_with(db, None, None);
     match def {
         GenericDefId::FunctionId(_) => (),
         GenericDefId::AdtId(adt) => {
             if let AdtId::StructId(id) = adt {
                 let flags = &db.struct_signature(id).flags;
                 if flags.contains(StructFlags::IS_UNSAFE_CELL) {
-                    return Some(Arc::from_iter(vec![Variance::Invariant; 1]));
+                    return VariancesOf::new_from_iter(interner, [Variance::Invariant]);
                 } else if flags.contains(StructFlags::IS_PHANTOM_DATA) {
-                    return Some(Arc::from_iter(vec![Variance::Covariant; 1]));
+                    return VariancesOf::new_from_iter(interner, [Variance::Covariant]);
                 }
             }
         }
-        _ => return None,
+        _ => return VariancesOf::new_from_iter(interner, []),
     }
 
     let generics = generics(db, def);
     let count = generics.len();
     if count == 0 {
-        return None;
+        return VariancesOf::new_from_iter(interner, []);
     }
     let mut variances =
         Context { generics, variances: vec![Variance::Bivariant; count], db }.solve();
@@ -69,7 +71,7 @@
         }
     }
 
-    variances.is_empty().not().then(|| Arc::from_iter(variances))
+    VariancesOf::new_from_iter(interner, variances)
 }
 
 // pub(crate) fn variances_of_cycle_fn(
@@ -81,130 +83,36 @@
 //     salsa::CycleRecoveryAction::Iterate
 // }
 
+fn glb(v1: Variance, v2: Variance) -> Variance {
+    // Greatest lower bound of the variance lattice as defined in The Paper:
+    //
+    //       *
+    //    -     +
+    //       o
+    match (v1, v2) {
+        (Variance::Invariant, _) | (_, Variance::Invariant) => Variance::Invariant,
+
+        (Variance::Covariant, Variance::Contravariant) => Variance::Invariant,
+        (Variance::Contravariant, Variance::Covariant) => Variance::Invariant,
+
+        (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
+
+        (Variance::Contravariant, Variance::Contravariant) => Variance::Contravariant,
+
+        (x, Variance::Bivariant) | (Variance::Bivariant, x) => x,
+    }
+}
+
 pub(crate) fn variances_of_cycle_initial(
     db: &dyn HirDatabase,
     def: GenericDefId,
-) -> Option<Arc<[Variance]>> {
+) -> VariancesOf<'_> {
+    let interner = DbInterner::new_with(db, None, None);
     let generics = generics(db, def);
     let count = generics.len();
 
-    if count == 0 {
-        return None;
-    }
     // FIXME(next-solver): Returns `Invariance` and not `Bivariance` here, see the comment in the main query.
-    Some(Arc::from(vec![Variance::Invariant; count]))
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum Variance {
-    Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
-    Invariant,     // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
-    Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type
-    Bivariant,     // T<A> <: T<B>            -- e.g., unused type parameter
-}
-
-impl fmt::Display for Variance {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Variance::Covariant => write!(f, "covariant"),
-            Variance::Invariant => write!(f, "invariant"),
-            Variance::Contravariant => write!(f, "contravariant"),
-            Variance::Bivariant => write!(f, "bivariant"),
-        }
-    }
-}
-
-impl Variance {
-    /// `a.xform(b)` combines the variance of a context with the
-    /// variance of a type with the following meaning. If we are in a
-    /// context with variance `a`, and we encounter a type argument in
-    /// a position with variance `b`, then `a.xform(b)` is the new
-    /// variance with which the argument appears.
-    ///
-    /// Example 1:
-    /// ```ignore (illustrative)
-    /// *mut Vec<i32>
-    /// ```
-    /// Here, the "ambient" variance starts as covariant. `*mut T` is
-    /// invariant with respect to `T`, so the variance in which the
-    /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
-    /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
-    /// respect to its type argument `T`, and hence the variance of
-    /// the `i32` here is `Invariant.xform(Covariant)`, which results
-    /// (again) in `Invariant`.
-    ///
-    /// Example 2:
-    /// ```ignore (illustrative)
-    /// fn(*const Vec<i32>, *mut Vec<i32)
-    /// ```
-    /// The ambient variance is covariant. A `fn` type is
-    /// contravariant with respect to its parameters, so the variance
-    /// within which both pointer types appear is
-    /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
-    /// T` is covariant with respect to `T`, so the variance within
-    /// which the first `Vec<i32>` appears is
-    /// `Contravariant.xform(Covariant)` or `Contravariant`. The same
-    /// is true for its `i32` argument. In the `*mut T` case, the
-    /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
-    /// and hence the outermost type is `Invariant` with respect to
-    /// `Vec<i32>` (and its `i32` argument).
-    ///
-    /// Source: Figure 1 of "Taming the Wildcards:
-    /// Combining Definition- and Use-Site Variance" published in PLDI'11.
-    fn xform(self, v: Variance) -> Variance {
-        match (self, v) {
-            // Figure 1, column 1.
-            (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
-            (Variance::Covariant, Variance::Contravariant) => Variance::Contravariant,
-            (Variance::Covariant, Variance::Invariant) => Variance::Invariant,
-            (Variance::Covariant, Variance::Bivariant) => Variance::Bivariant,
-
-            // Figure 1, column 2.
-            (Variance::Contravariant, Variance::Covariant) => Variance::Contravariant,
-            (Variance::Contravariant, Variance::Contravariant) => Variance::Covariant,
-            (Variance::Contravariant, Variance::Invariant) => Variance::Invariant,
-            (Variance::Contravariant, Variance::Bivariant) => Variance::Bivariant,
-
-            // Figure 1, column 3.
-            (Variance::Invariant, _) => Variance::Invariant,
-
-            // Figure 1, column 4.
-            (Variance::Bivariant, _) => Variance::Bivariant,
-        }
-    }
-
-    fn glb(self, v: Variance) -> Variance {
-        // Greatest lower bound of the variance lattice as
-        // defined in The Paper:
-        //
-        //       *
-        //    -     +
-        //       o
-        match (self, v) {
-            (Variance::Invariant, _) | (_, Variance::Invariant) => Variance::Invariant,
-
-            (Variance::Covariant, Variance::Contravariant) => Variance::Invariant,
-            (Variance::Contravariant, Variance::Covariant) => Variance::Invariant,
-
-            (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
-
-            (Variance::Contravariant, Variance::Contravariant) => Variance::Contravariant,
-
-            (x, Variance::Bivariant) | (Variance::Bivariant, x) => x,
-        }
-    }
-
-    pub fn invariant(self) -> Self {
-        self.xform(Variance::Invariant)
-    }
-
-    pub fn covariant(self) -> Self {
-        self.xform(Variance::Covariant)
-    }
-
-    pub fn contravariant(self) -> Self {
-        self.xform(Variance::Contravariant)
-    }
+    VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Invariant, count))
 }
 
 struct Context<'db> {
@@ -213,17 +121,16 @@
     variances: Vec<Variance>,
 }
 
-impl Context<'_> {
+impl<'db> Context<'db> {
     fn solve(mut self) -> Vec<Variance> {
         tracing::debug!("solve(generics={:?})", self.generics);
         match self.generics.def() {
             GenericDefId::AdtId(adt) => {
                 let db = self.db;
                 let mut add_constraints_from_variant = |variant| {
-                    let subst = self.generics.placeholder_subst(db);
-                    for (_, field) in db.field_types(variant).iter() {
+                    for (_, field) in db.field_types_ns(variant).iter() {
                         self.add_constraints_from_ty(
-                            &field.clone().substitute(Interner, &subst),
+                            field.instantiate_identity(),
                             Variance::Covariant,
                         );
                     }
@@ -239,16 +146,9 @@
                 }
             }
             GenericDefId::FunctionId(f) => {
-                let subst = self.generics.placeholder_subst(self.db);
-                let interner = DbInterner::new_with(self.db, None, None);
-                let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
-                let sig = self
-                    .db
-                    .callable_item_signature(f.into())
-                    .instantiate(interner, args)
-                    .skip_binder()
-                    .to_chalk(interner);
-                self.add_constraints_from_sig(sig.params_and_return.iter(), Variance::Covariant);
+                let sig =
+                    self.db.callable_item_signature(f.into()).instantiate_identity().skip_binder();
+                self.add_constraints_from_sig(sig.inputs_and_output.iter(), Variance::Covariant);
             }
             _ => {}
         }
@@ -276,122 +176,102 @@
     /// Adds constraints appropriate for an instance of `ty` appearing
     /// in a context with the generics defined in `generics` and
     /// ambient variance `variance`
-    fn add_constraints_from_ty(&mut self, ty: &Ty, variance: Variance) {
+    fn add_constraints_from_ty(&mut self, ty: Ty<'db>, variance: Variance) {
         tracing::debug!("add_constraints_from_ty(ty={:?}, variance={:?})", ty, variance);
-        match ty.kind(Interner) {
-            TyKind::Scalar(_) | TyKind::Never | TyKind::Str | TyKind::Foreign(..) => {
+        match ty.kind() {
+            TyKind::Int(_)
+            | TyKind::Uint(_)
+            | TyKind::Float(_)
+            | TyKind::Char
+            | TyKind::Bool
+            | TyKind::Never
+            | TyKind::Str
+            | TyKind::Foreign(..) => {
                 // leaf type -- noop
             }
-            TyKind::FnDef(..) | TyKind::Coroutine(..) | TyKind::Closure(..) => {
+            TyKind::FnDef(..)
+            | TyKind::Coroutine(..)
+            | TyKind::CoroutineClosure(..)
+            | TyKind::Closure(..) => {
                 never!("Unexpected unnameable type in variance computation: {:?}", ty);
             }
-            TyKind::Ref(mutbl, lifetime, ty) => {
+            TyKind::Ref(lifetime, ty, mutbl) => {
                 self.add_constraints_from_region(lifetime, variance);
-                self.add_constraints_from_mt(ty, *mutbl, variance);
+                self.add_constraints_from_mt(ty, mutbl, variance);
             }
             TyKind::Array(typ, len) => {
-                self.add_constraints_from_const(len, variance);
+                self.add_constraints_from_const(len);
                 self.add_constraints_from_ty(typ, variance);
             }
             TyKind::Slice(typ) => {
                 self.add_constraints_from_ty(typ, variance);
             }
-            TyKind::Raw(mutbl, ty) => {
-                self.add_constraints_from_mt(ty, *mutbl, variance);
+            TyKind::RawPtr(ty, mutbl) => {
+                self.add_constraints_from_mt(ty, mutbl, variance);
             }
-            TyKind::Tuple(_, subtys) => {
-                for subty in subtys.type_parameters(Interner) {
-                    self.add_constraints_from_ty(&subty, variance);
+            TyKind::Tuple(subtys) => {
+                for subty in subtys {
+                    self.add_constraints_from_ty(subty, variance);
                 }
             }
             TyKind::Adt(def, args) => {
-                self.add_constraints_from_args(def.0.into(), args.as_slice(Interner), variance);
+                self.add_constraints_from_args(def.def_id().0.into(), args, variance);
             }
-            TyKind::Alias(AliasTy::Opaque(opaque)) => {
-                self.add_constraints_from_invariant_args(
-                    opaque.substitution.as_slice(Interner),
-                    variance,
-                );
+            TyKind::Alias(_, alias) => {
+                // FIXME: Probably not correct wrt. opaques.
+                self.add_constraints_from_invariant_args(alias.args);
             }
-            TyKind::Alias(AliasTy::Projection(proj)) => {
-                self.add_constraints_from_invariant_args(
-                    proj.substitution.as_slice(Interner),
-                    variance,
-                );
-            }
-            // FIXME: check this
-            TyKind::AssociatedType(_, subst) => {
-                self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance);
-            }
-            // FIXME: check this
-            TyKind::OpaqueType(_, subst) => {
-                self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance);
-            }
-            TyKind::Dyn(it) => {
+            TyKind::Dynamic(bounds, region) => {
                 // The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
-                self.add_constraints_from_region(&it.lifetime, variance);
+                self.add_constraints_from_region(region, variance);
 
-                if let Some(trait_ref) = it.principal() {
-                    // Trait are always invariant so we can take advantage of that.
-                    self.add_constraints_from_invariant_args(
-                        trait_ref
-                            .map(|it| it.map(|it| it.substitution.clone()))
-                            .substitute(
-                                Interner,
-                                &[GenericArg::new(
-                                    Interner,
-                                    chalk_ir::GenericArgData::Ty(TyKind::Error.intern(Interner)),
-                                )],
-                            )
-                            .skip_binders()
-                            .as_slice(Interner),
-                        variance,
-                    );
+                for bound in bounds {
+                    match bound.skip_binder() {
+                        ExistentialPredicate::Trait(trait_ref) => {
+                            self.add_constraints_from_invariant_args(trait_ref.args)
+                        }
+                        ExistentialPredicate::Projection(projection) => {
+                            self.add_constraints_from_invariant_args(projection.args);
+                            match projection.term {
+                                Term::Ty(ty) => {
+                                    self.add_constraints_from_ty(ty, Variance::Invariant)
+                                }
+                                Term::Const(konst) => self.add_constraints_from_const(konst),
+                            }
+                        }
+                        ExistentialPredicate::AutoTrait(_) => {}
+                    }
                 }
-
-                // FIXME
-                // for projection in data.projection_bounds() {
-                //     match projection.skip_binder().term.unpack() {
-                //         TyKind::TermKind::Ty(ty) => {
-                //             self.add_constraints_from_ty( ty, self.invariant);
-                //         }
-                //         TyKind::TermKind::Const(c) => {
-                //             self.add_constraints_from_const( c, self.invariant)
-                //         }
-                //     }
-                // }
             }
 
             // Chalk has no params, so use placeholders for now?
-            TyKind::Placeholder(index) => {
-                let idx = crate::from_placeholder_idx(self.db, *index).0;
-                let index = self.generics.type_or_const_param_idx(idx).unwrap();
-                self.constrain(index, variance);
+            TyKind::Param(param) => self.constrain(param.index as usize, variance),
+            TyKind::FnPtr(sig, _) => {
+                self.add_constraints_from_sig(sig.skip_binder().inputs_and_output.iter(), variance);
             }
-            TyKind::Function(f) => {
-                self.add_constraints_from_sig(
-                    f.substitution.0.iter(Interner).filter_map(move |p| p.ty(Interner)),
-                    variance,
-                );
-            }
-            TyKind::Error => {
+            TyKind::Error(_) => {
                 // we encounter this when walking the trait references for object
                 // types, where we use Error as the Self type
             }
-            TyKind::CoroutineWitness(..) | TyKind::BoundVar(..) | TyKind::InferenceVar(..) => {
+            TyKind::Bound(..) => {}
+            TyKind::CoroutineWitness(..)
+            | TyKind::Placeholder(..)
+            | TyKind::Infer(..)
+            | TyKind::UnsafeBinder(..)
+            | TyKind::Pat(..) => {
                 never!("unexpected type encountered in variance inference: {:?}", ty)
             }
         }
     }
 
-    fn add_constraints_from_invariant_args(&mut self, args: &[GenericArg], variance: Variance) {
-        let variance_i = variance.invariant();
-
-        for k in args {
-            match k.data(Interner) {
-                GenericArgData::Lifetime(lt) => self.add_constraints_from_region(lt, variance_i),
-                GenericArgData::Ty(ty) => self.add_constraints_from_ty(ty, variance_i),
-                GenericArgData::Const(val) => self.add_constraints_from_const(val, variance_i),
+    fn add_constraints_from_invariant_args(&mut self, args: GenericArgs<'db>) {
+        for k in args.iter() {
+            match k {
+                GenericArg::Lifetime(lt) => {
+                    self.add_constraints_from_region(lt, Variance::Invariant)
+                }
+                GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, Variance::Invariant),
+                GenericArg::Const(val) => self.add_constraints_from_const(val),
             }
         }
     }
@@ -401,51 +281,40 @@
     fn add_constraints_from_args(
         &mut self,
         def_id: GenericDefId,
-        args: &[GenericArg],
+        args: GenericArgs<'db>,
         variance: Variance,
     ) {
-        // We don't record `inferred_starts` entries for empty generics.
         if args.is_empty() {
             return;
         }
-        let Some(variances) = self.db.variances_of(def_id) else {
-            return;
-        };
+        let variances = self.db.variances_of(def_id);
 
-        for (i, k) in args.iter().enumerate() {
-            match k.data(Interner) {
-                GenericArgData::Lifetime(lt) => {
-                    self.add_constraints_from_region(lt, variance.xform(variances[i]))
-                }
-                GenericArgData::Ty(ty) => {
-                    self.add_constraints_from_ty(ty, variance.xform(variances[i]))
-                }
-                GenericArgData::Const(val) => self.add_constraints_from_const(val, variance),
+        for (k, v) in args.iter().zip(variances) {
+            match k {
+                GenericArg::Lifetime(lt) => self.add_constraints_from_region(lt, variance.xform(v)),
+                GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, variance.xform(v)),
+                GenericArg::Const(val) => self.add_constraints_from_const(val),
             }
         }
     }
 
     /// Adds constraints appropriate for a const expression `val`
     /// in a context with ambient variance `variance`
-    fn add_constraints_from_const(&mut self, c: &Const, variance: Variance) {
-        match &c.data(Interner).value {
-            chalk_ir::ConstValue::Concrete(c) => {
-                if let ConstScalar::UnevaluatedConst(_, subst) = &c.interned {
-                    self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance);
-                }
-            }
+    fn add_constraints_from_const(&mut self, c: Const<'db>) {
+        match c.kind() {
+            ConstKind::Unevaluated(c) => self.add_constraints_from_invariant_args(c.args),
             _ => {}
         }
     }
 
     /// Adds constraints appropriate for a function with signature
     /// `sig` appearing in a context with ambient variance `variance`
-    fn add_constraints_from_sig<'a>(
+    fn add_constraints_from_sig(
         &mut self,
-        mut sig_tys: impl DoubleEndedIterator<Item = &'a Ty>,
+        mut sig_tys: impl DoubleEndedIterator<Item = Ty<'db>>,
         variance: Variance,
     ) {
-        let contra = variance.contravariant();
+        let contra = variance.xform(Variance::Contravariant);
         let Some(output) = sig_tys.next_back() else {
             return never!("function signature has no return type");
         };
@@ -457,27 +326,26 @@
 
     /// Adds constraints appropriate for a region appearing in a
     /// context with ambient variance `variance`
-    fn add_constraints_from_region(&mut self, region: &Lifetime, variance: Variance) {
+    fn add_constraints_from_region(&mut self, region: Region<'db>, variance: Variance) {
         tracing::debug!(
             "add_constraints_from_region(region={:?}, variance={:?})",
             region,
             variance
         );
-        match region.data(Interner) {
-            LifetimeData::Placeholder(index) => {
-                let idx = crate::lt_from_placeholder_idx(self.db, *index).0;
-                let inferred = self.generics.lifetime_idx(idx).unwrap();
-                self.constrain(inferred, variance);
-            }
-            LifetimeData::Static => {}
-            LifetimeData::BoundVar(..) => {
+        match region.kind() {
+            RegionKind::ReEarlyParam(param) => self.constrain(param.index as usize, variance),
+            RegionKind::ReStatic => {}
+            RegionKind::ReBound(..) => {
                 // Either a higher-ranked region inside of a type or a
                 // late-bound function parameter.
                 //
                 // We do not compute constraints for either of these.
             }
-            LifetimeData::Error => {}
-            LifetimeData::Phantom(..) | LifetimeData::InferenceVar(..) | LifetimeData::Erased => {
+            RegionKind::ReError(_) => {}
+            RegionKind::ReLateParam(..)
+            | RegionKind::RePlaceholder(..)
+            | RegionKind::ReVar(..)
+            | RegionKind::ReErased => {
                 // We don't expect to see anything but 'static or bound
                 // regions when visiting member types or method types.
                 never!(
@@ -491,11 +359,11 @@
 
     /// Adds constraints appropriate for a mutability-type pair
     /// appearing in a context with ambient variance `variance`
-    fn add_constraints_from_mt(&mut self, ty: &Ty, mt: Mutability, variance: Variance) {
+    fn add_constraints_from_mt(&mut self, ty: Ty<'db>, mt: Mutability, variance: Variance) {
         self.add_constraints_from_ty(
             ty,
             match mt {
-                Mutability::Mut => variance.invariant(),
+                Mutability::Mut => Variance::Invariant,
                 Mutability::Not => variance,
             },
         );
@@ -508,7 +376,7 @@
             self.variances[index],
             variance
         );
-        self.variances[index] = self.variances[index].glb(variance);
+        self.variances[index] = glb(self.variances[index], variance);
     }
 }
 
@@ -519,6 +387,7 @@
         AdtId, GenericDefId, ModuleDefId, hir::generics::GenericParamDataRef, src::HasSource,
     };
     use itertools::Itertools;
+    use rustc_type_ir::{Variance, inherent::SliceLike};
     use stdx::format_to;
     use syntax::{AstNode, ast::HasName};
     use test_fixture::WithFixture;
@@ -1037,26 +906,21 @@
                                 let loc = it.lookup(&db);
                                 loc.source(&db).value.name().unwrap()
                             }
-                            GenericDefId::TraitId(it) => {
-                                let loc = it.lookup(&db);
-                                loc.source(&db).value.name().unwrap()
-                            }
-                            GenericDefId::TypeAliasId(it) => {
-                                let loc = it.lookup(&db);
-                                loc.source(&db).value.name().unwrap()
-                            }
-                            GenericDefId::ImplId(_) => return None,
-                            GenericDefId::ConstId(_) => return None,
-                            GenericDefId::StaticId(_) => return None,
+                            GenericDefId::TraitId(_)
+                            | GenericDefId::TypeAliasId(_)
+                            | GenericDefId::ImplId(_)
+                            | GenericDefId::ConstId(_)
+                            | GenericDefId::StaticId(_) => return None,
                         },
                     ))
                 })
                 .sorted_by_key(|(_, n)| n.syntax().text_range().start());
             let mut res = String::new();
             for (def, name) in defs {
-                let Some(variances) = db.variances_of(def) else {
+                let variances = db.variances_of(def);
+                if variances.is_empty() {
                     continue;
-                };
+                }
                 format_to!(
                     res,
                     "{name}[{}]\n",
@@ -1072,10 +936,16 @@
                                 &lifetime_param_data.name
                             }
                         })
-                        .zip_eq(&*variances)
+                        .zip_eq(variances)
                         .format_with(", ", |(name, var), f| f(&format_args!(
-                            "{}: {var}",
-                            name.as_str()
+                            "{}: {}",
+                            name.as_str(),
+                            match var {
+                                Variance::Covariant => "covariant",
+                                Variance::Invariant => "invariant",
+                                Variance::Contravariant => "contravariant",
+                                Variance::Bivariant => "bivariant",
+                            },
                         )))
                 );
             }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index fc516a6..36c8c30 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -36,6 +36,7 @@
 mod display;
 
 use std::{
+    fmt,
     mem::discriminant,
     ops::{ControlFlow, Not},
 };
@@ -160,7 +161,7 @@
     // FIXME: Properly encapsulate mir
     hir_ty::mir,
     hir_ty::{
-        CastError, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change,
+        CastError, FnAbi, PointerCast, attach_db, attach_db_allow_change,
         consteval::ConstEvalError,
         diagnostics::UnsafetyReason,
         display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite},
@@ -4110,7 +4111,39 @@
             GenericParam::ConstParam(_) => return None,
             GenericParam::LifetimeParam(it) => generics.lifetime_idx(it.id)?,
         };
-        db.variances_of(parent)?.get(index).copied()
+        db.variances_of(parent).get(index).map(Into::into)
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Variance {
+    Bivariant,
+    Covariant,
+    Contravariant,
+    Invariant,
+}
+
+impl From<rustc_type_ir::Variance> for Variance {
+    #[inline]
+    fn from(value: rustc_type_ir::Variance) -> Self {
+        match value {
+            rustc_type_ir::Variance::Covariant => Variance::Covariant,
+            rustc_type_ir::Variance::Invariant => Variance::Invariant,
+            rustc_type_ir::Variance::Contravariant => Variance::Contravariant,
+            rustc_type_ir::Variance::Bivariant => Variance::Bivariant,
+        }
+    }
+}
+
+impl fmt::Display for Variance {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let description = match self {
+            Variance::Bivariant => "bivariant",
+            Variance::Covariant => "covariant",
+            Variance::Contravariant => "contravariant",
+            Variance::Invariant => "invariant",
+        };
+        f.pad(description)
     }
 }