Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/ty.rs')
-rw-r--r--crates/hir-ty/src/next_solver/ty.rs1340
1 files changed, 1340 insertions, 0 deletions
diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs
new file mode 100644
index 0000000000..b8406fecda
--- /dev/null
+++ b/crates/hir-ty/src/next_solver/ty.rs
@@ -0,0 +1,1340 @@
+//! Things related to tys in the next-trait-solver.
+
+use std::ops::ControlFlow;
+
+use hir_def::{
+ AdtId, HasModule, TypeParamId,
+ hir::generics::{TypeOrConstParamData, TypeParamProvenance},
+ lang_item::LangItem,
+};
+use hir_def::{TraitId, type_ref::Rawness};
+use rustc_abi::{Float, Integer, Size};
+use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult};
+use rustc_type_ir::{
+ AliasTyKind, BoundVar, BoundVarIndexKind, ClosureKind, CoroutineArgs, CoroutineArgsParts,
+ DebruijnIndex, FlagComputation, Flags, FloatTy, FloatVid, InferTy, IntTy, IntVid, Interner,
+ TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+ TypeVisitor, UintTy, Upcast, WithCachedTypeInfo,
+ inherent::{
+ AdtDef as _, BoundExistentialPredicates, BoundVarLike, Const as _, GenericArgs as _,
+ IntoKind, ParamLike, PlaceholderLike, Safety as _, SliceLike, Ty as _,
+ },
+ relate::Relate,
+ solve::SizedTraitKind,
+ walk::TypeWalker,
+};
+
+use crate::{
+ ImplTraitId,
+ db::{HirDatabase, InternedCoroutine},
+ next_solver::{
+ AdtDef, AliasTy, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const,
+ CoroutineIdWrapper, FnSig, GenericArg, PolyFnSig, Region, TraitRef, TypeAliasIdWrapper,
+ abi::Safety,
+ interner::InternedWrapperNoDebug,
+ util::{CoroutineArgsExt, IntegerTypeExt},
+ },
+};
+
+use super::{
+ BoundVarKind, DbInterner, GenericArgs, Placeholder, SolverDefId, interned_vec_db,
+ util::{FloatExt, IntegerExt},
+};
+
+pub type TyKind<'db> = rustc_type_ir::TyKind<DbInterner<'db>>;
+pub type FnHeader<'db> = rustc_type_ir::FnHeader<DbInterner<'db>>;
+
+#[salsa::interned(constructor = new_)]
+pub struct Ty<'db> {
+ #[returns(ref)]
+ kind_: InternedWrapperNoDebug<WithCachedTypeInfo<TyKind<'db>>>,
+}
+
+const _: () = {
+ const fn is_copy<T: Copy>() {}
+ is_copy::<Ty<'static>>();
+};
+
+impl<'db> Ty<'db> {
+ pub fn new(interner: DbInterner<'db>, kind: TyKind<'db>) -> Self {
+ let flags = FlagComputation::for_kind(&kind);
+ let cached = WithCachedTypeInfo {
+ internee: kind,
+ flags: flags.flags,
+ outer_exclusive_binder: flags.outer_exclusive_binder,
+ };
+ Ty::new_(interner.db(), InternedWrapperNoDebug(cached))
+ }
+
+ pub fn inner(&self) -> &WithCachedTypeInfo<TyKind<'db>> {
+ crate::with_attached_db(|db| {
+ let inner = &self.kind_(db).0;
+ // SAFETY: The caller already has access to a `Ty<'db>`, so borrowchecking will
+ // make sure that our returned value is valid for the lifetime `'db`.
+ unsafe { std::mem::transmute(inner) }
+ })
+ }
+
+ pub fn new_adt(interner: DbInterner<'db>, adt_id: AdtId, args: GenericArgs<'db>) -> Self {
+ Ty::new(interner, TyKind::Adt(AdtDef::new(adt_id, interner), args))
+ }
+
+ pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32) -> Self {
+ Ty::new(interner, TyKind::Param(ParamTy { id, index }))
+ }
+
+ pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderTy) -> Self {
+ Ty::new(interner, TyKind::Placeholder(placeholder))
+ }
+
+ pub fn new_infer(interner: DbInterner<'db>, infer: InferTy) -> Self {
+ Ty::new(interner, TyKind::Infer(infer))
+ }
+
+ pub fn new_int_var(interner: DbInterner<'db>, v: IntVid) -> Self {
+ Ty::new_infer(interner, InferTy::IntVar(v))
+ }
+
+ pub fn new_float_var(interner: DbInterner<'db>, v: FloatVid) -> Self {
+ Ty::new_infer(interner, InferTy::FloatVar(v))
+ }
+
+ pub fn new_int(interner: DbInterner<'db>, i: IntTy) -> Self {
+ Ty::new(interner, TyKind::Int(i))
+ }
+
+ pub fn new_uint(interner: DbInterner<'db>, ui: UintTy) -> Self {
+ Ty::new(interner, TyKind::Uint(ui))
+ }
+
+ pub fn new_float(interner: DbInterner<'db>, f: FloatTy) -> Self {
+ Ty::new(interner, TyKind::Float(f))
+ }
+
+ pub fn new_fresh(interner: DbInterner<'db>, n: u32) -> Self {
+ Ty::new_infer(interner, InferTy::FreshTy(n))
+ }
+
+ pub fn new_fresh_int(interner: DbInterner<'db>, n: u32) -> Self {
+ Ty::new_infer(interner, InferTy::FreshIntTy(n))
+ }
+
+ pub fn new_fresh_float(interner: DbInterner<'db>, n: u32) -> Self {
+ Ty::new_infer(interner, InferTy::FreshFloatTy(n))
+ }
+
+ pub fn new_empty_tuple(interner: DbInterner<'db>) -> Self {
+ Ty::new_tup(interner, &[])
+ }
+
+ /// Returns the `Size` for primitive types (bool, uint, int, char, float).
+ pub fn primitive_size(self, interner: DbInterner<'db>) -> Size {
+ match self.kind() {
+ TyKind::Bool => Size::from_bytes(1),
+ TyKind::Char => Size::from_bytes(4),
+ TyKind::Int(ity) => Integer::from_int_ty(&interner, ity).size(),
+ TyKind::Uint(uty) => Integer::from_uint_ty(&interner, uty).size(),
+ TyKind::Float(fty) => Float::from_float_ty(fty).size(),
+ _ => panic!("non primitive type"),
+ }
+ }
+
+ pub fn int_size_and_signed(self, interner: DbInterner<'db>) -> (Size, bool) {
+ match self.kind() {
+ TyKind::Int(ity) => (Integer::from_int_ty(&interner, ity).size(), true),
+ TyKind::Uint(uty) => (Integer::from_uint_ty(&interner, uty).size(), false),
+ _ => panic!("non integer discriminant"),
+ }
+ }
+
+ pub fn walk(self) -> TypeWalker<DbInterner<'db>> {
+ TypeWalker::new(self.into())
+ }
+
+ /// Fast path helper for testing if a type is `Sized` or `MetaSized`.
+ ///
+ /// Returning true means the type is known to implement the sizedness trait. Returning `false`
+ /// means nothing -- could be sized, might not be.
+ ///
+ /// Note that we could never rely on the fact that a type such as `[_]` is trivially `!Sized`
+ /// because we could be in a type environment with a bound such as `[_]: Copy`. A function with
+ /// such a bound obviously never can be called, but that doesn't mean it shouldn't typecheck.
+ /// This is why this method doesn't return `Option<bool>`.
+ #[tracing::instrument(skip(tcx), level = "debug")]
+ pub fn has_trivial_sizedness(self, tcx: DbInterner<'db>, sizedness: SizedTraitKind) -> bool {
+ match self.kind() {
+ TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_))
+ | TyKind::Uint(_)
+ | TyKind::Int(_)
+ | TyKind::Bool
+ | TyKind::Float(_)
+ | TyKind::FnDef(..)
+ | TyKind::FnPtr(..)
+ | TyKind::UnsafeBinder(_)
+ | TyKind::RawPtr(..)
+ | TyKind::Char
+ | TyKind::Ref(..)
+ | TyKind::Coroutine(..)
+ | TyKind::CoroutineWitness(..)
+ | TyKind::Array(..)
+ | TyKind::Pat(..)
+ | TyKind::Closure(..)
+ | TyKind::CoroutineClosure(..)
+ | TyKind::Never
+ | TyKind::Error(_) => true,
+
+ TyKind::Str | TyKind::Slice(_) | TyKind::Dynamic(_, _) => match sizedness {
+ SizedTraitKind::Sized => false,
+ SizedTraitKind::MetaSized => true,
+ },
+
+ TyKind::Foreign(..) => match sizedness {
+ SizedTraitKind::Sized | SizedTraitKind::MetaSized => false,
+ },
+
+ TyKind::Tuple(tys) => {
+ tys.last().is_none_or(|ty| ty.has_trivial_sizedness(tcx, sizedness))
+ }
+
+ TyKind::Adt(def, args) => def
+ .sizedness_constraint(tcx, sizedness)
+ .is_none_or(|ty| ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness)),
+
+ TyKind::Alias(..) | TyKind::Param(_) | TyKind::Placeholder(..) | TyKind::Bound(..) => {
+ false
+ }
+
+ TyKind::Infer(InferTy::TyVar(_)) => false,
+
+ TyKind::Infer(
+ InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_),
+ ) => {
+ panic!("`has_trivial_sizedness` applied to unexpected type: {self:?}")
+ }
+ }
+ }
+
+ /// Fast path helper for primitives which are always `Copy` and which
+ /// have a side-effect-free `Clone` impl.
+ ///
+ /// Returning true means the type is known to be pure and `Copy+Clone`.
+ /// Returning `false` means nothing -- could be `Copy`, might not be.
+ ///
+ /// This is mostly useful for optimizations, as these are the types
+ /// on which we can replace cloning with dereferencing.
+ pub fn is_trivially_pure_clone_copy(self) -> bool {
+ match self.kind() {
+ TyKind::Bool | TyKind::Char | TyKind::Never => true,
+
+ // These aren't even `Clone`
+ TyKind::Str | TyKind::Slice(..) | TyKind::Foreign(..) | TyKind::Dynamic(..) => false,
+
+ TyKind::Infer(InferTy::FloatVar(_) | InferTy::IntVar(_))
+ | TyKind::Int(..)
+ | TyKind::Uint(..)
+ | TyKind::Float(..) => true,
+
+ // ZST which can't be named are fine.
+ TyKind::FnDef(..) => true,
+
+ TyKind::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(),
+
+ // A 100-tuple isn't "trivial", so doing this only for reasonable sizes.
+ TyKind::Tuple(field_tys) => {
+ field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy)
+ }
+
+ TyKind::Pat(ty, _) => ty.is_trivially_pure_clone_copy(),
+
+ // Sometimes traits aren't implemented for every ABI or arity,
+ // because we can't be generic over everything yet.
+ TyKind::FnPtr(..) => false,
+
+ // Definitely absolutely not copy.
+ TyKind::Ref(_, _, Mutability::Mut) => false,
+
+ // The standard library has a blanket Copy impl for shared references and raw pointers,
+ // for all unsized types.
+ TyKind::Ref(_, _, Mutability::Not) | TyKind::RawPtr(..) => true,
+
+ TyKind::Coroutine(..) | TyKind::CoroutineWitness(..) => false,
+
+ // Might be, but not "trivial" so just giving the safe answer.
+ TyKind::Adt(..) | TyKind::Closure(..) | TyKind::CoroutineClosure(..) => false,
+
+ TyKind::UnsafeBinder(_) => false,
+
+ // Needs normalization or revealing to determine, so no is the safe answer.
+ TyKind::Alias(..) => false,
+
+ TyKind::Param(..)
+ | TyKind::Placeholder(..)
+ | TyKind::Bound(..)
+ | TyKind::Infer(..)
+ | TyKind::Error(..) => false,
+ }
+ }
+
+ pub fn is_trivially_wf(self, tcx: DbInterner<'db>) -> bool {
+ match self.kind() {
+ TyKind::Bool
+ | TyKind::Char
+ | TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_)
+ | TyKind::Str
+ | TyKind::Never
+ | TyKind::Param(_)
+ | TyKind::Placeholder(_)
+ | TyKind::Bound(..) => true,
+
+ TyKind::Slice(ty) => {
+ ty.is_trivially_wf(tcx) && ty.has_trivial_sizedness(tcx, SizedTraitKind::Sized)
+ }
+ TyKind::RawPtr(ty, _) => ty.is_trivially_wf(tcx),
+
+ TyKind::FnPtr(sig_tys, _) => {
+ sig_tys.skip_binder().inputs_and_output.iter().all(|ty| ty.is_trivially_wf(tcx))
+ }
+ TyKind::Ref(_, ty, _) => ty.is_global() && ty.is_trivially_wf(tcx),
+
+ TyKind::Infer(infer) => match infer {
+ InferTy::TyVar(_) => false,
+ InferTy::IntVar(_) | InferTy::FloatVar(_) => true,
+ InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_) => true,
+ },
+
+ TyKind::Adt(_, _)
+ | TyKind::Tuple(_)
+ | TyKind::Array(..)
+ | TyKind::Foreign(_)
+ | TyKind::Pat(_, _)
+ | TyKind::FnDef(..)
+ | TyKind::UnsafeBinder(..)
+ | TyKind::Dynamic(..)
+ | TyKind::Closure(..)
+ | TyKind::CoroutineClosure(..)
+ | TyKind::Coroutine(..)
+ | TyKind::CoroutineWitness(..)
+ | TyKind::Alias(..)
+ | TyKind::Error(_) => false,
+ }
+ }
+
+ #[inline]
+ pub fn is_never(self) -> bool {
+ matches!(self.kind(), TyKind::Never)
+ }
+
+ #[inline]
+ pub fn is_infer(self) -> bool {
+ matches!(self.kind(), TyKind::Infer(..))
+ }
+
+ #[inline]
+ pub fn is_str(self) -> bool {
+ matches!(self.kind(), TyKind::Str)
+ }
+
+ #[inline]
+ pub fn is_unit(self) -> bool {
+ matches!(self.kind(), TyKind::Tuple(tys) if tys.inner().is_empty())
+ }
+
+ #[inline]
+ pub fn is_raw_ptr(self) -> bool {
+ matches!(self.kind(), TyKind::RawPtr(..))
+ }
+
+ pub fn is_union(self) -> bool {
+ self.as_adt().is_some_and(|(adt, _)| matches!(adt, AdtId::UnionId(_)))
+ }
+
+ #[inline]
+ pub fn as_adt(self) -> Option<(AdtId, GenericArgs<'db>)> {
+ match self.kind() {
+ TyKind::Adt(adt_def, args) => Some((adt_def.def_id().0, args)),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn ty_vid(self) -> Option<TyVid> {
+ match self.kind() {
+ TyKind::Infer(rustc_type_ir::TyVar(vid)) => Some(vid),
+ _ => None,
+ }
+ }
+
+ /// Given a `fn` type, returns an equivalent `unsafe fn` type;
+ /// that is, a `fn` type that is equivalent in every way for being
+ /// unsafe.
+ pub fn safe_to_unsafe_fn_ty(interner: DbInterner<'db>, sig: PolyFnSig<'db>) -> Ty<'db> {
+ assert!(sig.safety().is_safe());
+ Ty::new_fn_ptr(interner, sig.map_bound(|sig| FnSig { safety: Safety::Unsafe, ..sig }))
+ }
+
+ /// Returns the type of `*ty`.
+ ///
+ /// The parameter `explicit` indicates if this is an *explicit* dereference.
+ /// Some types -- notably raw ptrs -- can only be dereferenced explicitly.
+ pub fn builtin_deref(self, db: &dyn HirDatabase, explicit: bool) -> Option<Ty<'db>> {
+ match self.kind() {
+ TyKind::Adt(adt, substs) if crate::lang_items::is_box(db, adt.def_id().0) => {
+ Some(substs.as_slice()[0].expect_ty())
+ }
+ TyKind::Ref(_, ty, _) => Some(ty),
+ TyKind::RawPtr(ty, _) if explicit => Some(ty),
+ _ => None,
+ }
+ }
+
+ /// Whether the type contains some non-lifetime, aka. type or const, error type.
+ pub fn references_non_lt_error(self) -> bool {
+ references_non_lt_error(&self)
+ }
+
+ pub fn callable_sig(self, interner: DbInterner<'db>) -> Option<Binder<'db, FnSig<'db>>> {
+ match self.kind() {
+ TyKind::FnDef(callable, args) => {
+ Some(interner.fn_sig(callable).instantiate(interner, args))
+ }
+ TyKind::FnPtr(sig, hdr) => Some(sig.with(hdr)),
+ TyKind::Closure(_, closure_args) => closure_args
+ .split_closure_args_untupled()
+ .closure_sig_as_fn_ptr_ty
+ .callable_sig(interner),
+ TyKind::CoroutineClosure(coroutine_id, args) => {
+ Some(args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
+ let unit_ty = Ty::new_unit(interner);
+ let return_ty = Ty::new_coroutine(
+ interner,
+ coroutine_id,
+ CoroutineArgs::new(
+ interner,
+ CoroutineArgsParts {
+ parent_args: args.as_coroutine_closure().parent_args(),
+ kind_ty: unit_ty,
+ resume_ty: unit_ty,
+ yield_ty: unit_ty,
+ return_ty: sig.return_ty,
+ // FIXME: Deduce this from the coroutine closure's upvars.
+ tupled_upvars_ty: unit_ty,
+ },
+ )
+ .args,
+ );
+ FnSig {
+ inputs_and_output: Tys::new_from_iter(
+ interner,
+ sig.tupled_inputs_ty
+ .tuple_fields()
+ .iter()
+ .chain(std::iter::once(return_ty)),
+ ),
+ c_variadic: sig.c_variadic,
+ safety: sig.safety,
+ abi: sig.abi,
+ }
+ }))
+ }
+ _ => None,
+ }
+ }
+
+ pub fn as_reference(self) -> Option<(Ty<'db>, Region<'db>, Mutability)> {
+ match self.kind() {
+ TyKind::Ref(region, ty, mutability) => Some((ty, region, mutability)),
+ _ => None,
+ }
+ }
+
+ pub fn as_reference_or_ptr(self) -> Option<(Ty<'db>, Rawness, Mutability)> {
+ match self.kind() {
+ TyKind::Ref(_, ty, mutability) => Some((ty, Rawness::Ref, mutability)),
+ TyKind::RawPtr(ty, mutability) => Some((ty, Rawness::RawPtr, mutability)),
+ _ => None,
+ }
+ }
+
+ pub fn as_tuple(self) -> Option<Tys<'db>> {
+ match self.kind() {
+ TyKind::Tuple(tys) => Some(tys),
+ _ => None,
+ }
+ }
+
+ pub fn dyn_trait(self) -> Option<TraitId> {
+ let TyKind::Dynamic(bounds, _) = self.kind() else { return None };
+ Some(bounds.principal_def_id()?.0)
+ }
+
+ pub fn strip_references(self) -> Ty<'db> {
+ let mut t = self;
+ while let TyKind::Ref(_lifetime, ty, _mutability) = t.kind() {
+ t = ty;
+ }
+ t
+ }
+
+ pub fn strip_reference(self) -> Ty<'db> {
+ self.as_reference().map_or(self, |(ty, _, _)| ty)
+ }
+
+ /// Replace infer vars with errors.
+ ///
+ /// This needs to be called for every type that may contain infer vars and is yielded to outside inference,
+ /// as things other than inference do not expect to see infer vars.
+ pub fn replace_infer_with_error(self, interner: DbInterner<'db>) -> Ty<'db> {
+ self.fold_with(&mut crate::next_solver::infer::resolve::ReplaceInferWithError::new(
+ interner,
+ ))
+ }
+
+ pub fn from_builtin_type(
+ interner: DbInterner<'db>,
+ ty: hir_def::builtin_type::BuiltinType,
+ ) -> Ty<'db> {
+ let kind = match ty {
+ hir_def::builtin_type::BuiltinType::Char => TyKind::Char,
+ hir_def::builtin_type::BuiltinType::Bool => TyKind::Bool,
+ hir_def::builtin_type::BuiltinType::Str => TyKind::Str,
+ hir_def::builtin_type::BuiltinType::Int(int) => TyKind::Int(match int {
+ hir_def::builtin_type::BuiltinInt::Isize => rustc_type_ir::IntTy::Isize,
+ hir_def::builtin_type::BuiltinInt::I8 => rustc_type_ir::IntTy::I8,
+ hir_def::builtin_type::BuiltinInt::I16 => rustc_type_ir::IntTy::I16,
+ hir_def::builtin_type::BuiltinInt::I32 => rustc_type_ir::IntTy::I32,
+ hir_def::builtin_type::BuiltinInt::I64 => rustc_type_ir::IntTy::I64,
+ hir_def::builtin_type::BuiltinInt::I128 => rustc_type_ir::IntTy::I128,
+ }),
+ hir_def::builtin_type::BuiltinType::Uint(uint) => TyKind::Uint(match uint {
+ hir_def::builtin_type::BuiltinUint::Usize => rustc_type_ir::UintTy::Usize,
+ hir_def::builtin_type::BuiltinUint::U8 => rustc_type_ir::UintTy::U8,
+ hir_def::builtin_type::BuiltinUint::U16 => rustc_type_ir::UintTy::U16,
+ hir_def::builtin_type::BuiltinUint::U32 => rustc_type_ir::UintTy::U32,
+ hir_def::builtin_type::BuiltinUint::U64 => rustc_type_ir::UintTy::U64,
+ hir_def::builtin_type::BuiltinUint::U128 => rustc_type_ir::UintTy::U128,
+ }),
+ hir_def::builtin_type::BuiltinType::Float(float) => TyKind::Float(match float {
+ hir_def::builtin_type::BuiltinFloat::F16 => rustc_type_ir::FloatTy::F16,
+ hir_def::builtin_type::BuiltinFloat::F32 => rustc_type_ir::FloatTy::F32,
+ hir_def::builtin_type::BuiltinFloat::F64 => rustc_type_ir::FloatTy::F64,
+ hir_def::builtin_type::BuiltinFloat::F128 => rustc_type_ir::FloatTy::F128,
+ }),
+ };
+ Ty::new(interner, kind)
+ }
+
+ pub fn as_builtin(self) -> Option<hir_def::builtin_type::BuiltinType> {
+ let builtin = match self.kind() {
+ TyKind::Char => hir_def::builtin_type::BuiltinType::Char,
+ TyKind::Bool => hir_def::builtin_type::BuiltinType::Bool,
+ TyKind::Str => hir_def::builtin_type::BuiltinType::Str,
+ TyKind::Int(int) => hir_def::builtin_type::BuiltinType::Int(match int {
+ rustc_type_ir::IntTy::Isize => hir_def::builtin_type::BuiltinInt::Isize,
+ rustc_type_ir::IntTy::I8 => hir_def::builtin_type::BuiltinInt::I8,
+ rustc_type_ir::IntTy::I16 => hir_def::builtin_type::BuiltinInt::I16,
+ rustc_type_ir::IntTy::I32 => hir_def::builtin_type::BuiltinInt::I32,
+ rustc_type_ir::IntTy::I64 => hir_def::builtin_type::BuiltinInt::I64,
+ rustc_type_ir::IntTy::I128 => hir_def::builtin_type::BuiltinInt::I128,
+ }),
+ TyKind::Uint(uint) => hir_def::builtin_type::BuiltinType::Uint(match uint {
+ rustc_type_ir::UintTy::Usize => hir_def::builtin_type::BuiltinUint::Usize,
+ rustc_type_ir::UintTy::U8 => hir_def::builtin_type::BuiltinUint::U8,
+ rustc_type_ir::UintTy::U16 => hir_def::builtin_type::BuiltinUint::U16,
+ rustc_type_ir::UintTy::U32 => hir_def::builtin_type::BuiltinUint::U32,
+ rustc_type_ir::UintTy::U64 => hir_def::builtin_type::BuiltinUint::U64,
+ rustc_type_ir::UintTy::U128 => hir_def::builtin_type::BuiltinUint::U128,
+ }),
+ TyKind::Float(float) => hir_def::builtin_type::BuiltinType::Float(match float {
+ rustc_type_ir::FloatTy::F16 => hir_def::builtin_type::BuiltinFloat::F16,
+ rustc_type_ir::FloatTy::F32 => hir_def::builtin_type::BuiltinFloat::F32,
+ rustc_type_ir::FloatTy::F64 => hir_def::builtin_type::BuiltinFloat::F64,
+ rustc_type_ir::FloatTy::F128 => hir_def::builtin_type::BuiltinFloat::F128,
+ }),
+ _ => return None,
+ };
+ Some(builtin)
+ }
+
+ // FIXME: Should this be here?
+ pub fn impl_trait_bounds(self, db: &'db dyn HirDatabase) -> Option<Vec<Clause<'db>>> {
+ let interner = DbInterner::new_with(db, None, None);
+
+ match self.kind() {
+ TyKind::Alias(AliasTyKind::Opaque, opaque_ty) => {
+ match db.lookup_intern_impl_trait_id(opaque_ty.def_id.expect_opaque_ty()) {
+ ImplTraitId::ReturnTypeImplTrait(func, idx) => {
+ db.return_type_impl_traits(func).map(|it| {
+ let data =
+ (*it).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
+ data.iter_instantiated_copied(interner, opaque_ty.args.as_slice())
+ .collect()
+ })
+ }
+ ImplTraitId::TypeAliasImplTrait(alias, idx) => {
+ db.type_alias_impl_traits(alias).map(|it| {
+ let data =
+ (*it).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
+ data.iter_instantiated_copied(interner, opaque_ty.args.as_slice())
+ .collect()
+ })
+ }
+ }
+ }
+ TyKind::Param(param) => {
+ // FIXME: We shouldn't use `param.id` here.
+ let generic_params = db.generic_params(param.id.parent());
+ let param_data = &generic_params[param.id.local_id()];
+ match param_data {
+ TypeOrConstParamData::TypeParamData(p) => match p.provenance {
+ TypeParamProvenance::ArgumentImplTrait => {
+ let predicates = db
+ .generic_predicates(param.id.parent())
+ .instantiate_identity()
+ .into_iter()
+ .flatten()
+ .filter(|wc| match wc.kind().skip_binder() {
+ ClauseKind::Trait(tr) => tr.self_ty() == self,
+ ClauseKind::Projection(pred) => pred.self_ty() == self,
+ ClauseKind::TypeOutlives(pred) => pred.0 == self,
+ _ => false,
+ })
+ .collect::<Vec<_>>();
+
+ Some(predicates)
+ }
+ _ => None,
+ },
+ _ => None,
+ }
+ }
+ TyKind::Coroutine(coroutine_id, _args) => {
+ let InternedCoroutine(owner, _) = coroutine_id.0.loc(db);
+ let krate = owner.module(db).krate();
+ if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) {
+ // This is only used by type walking.
+ // Parameters will be walked outside, and projection predicate is not used.
+ // So just provide the Future trait.
+ let impl_bound = TraitRef::new(
+ interner,
+ future_trait.into(),
+ GenericArgs::new_from_iter(interner, []),
+ )
+ .upcast(interner);
+ Some(vec![impl_bound])
+ } else {
+ None
+ }
+ }
+ _ => None,
+ }
+ }
+
+ /// FIXME: Get rid of this, it's not a good abstraction
+ pub fn equals_ctor(self, other: Ty<'db>) -> bool {
+ match (self.kind(), other.kind()) {
+ (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt.def_id() == adt2.def_id(),
+ (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
+ true
+ }
+ (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
+ (TyKind::Alias(_, alias, ..), TyKind::Alias(_, alias2)) => {
+ alias.def_id == alias2.def_id
+ }
+ (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2,
+ (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
+ (TyKind::Ref(.., mutability), TyKind::Ref(.., mutability2))
+ | (TyKind::RawPtr(.., mutability), TyKind::RawPtr(.., mutability2)) => {
+ mutability == mutability2
+ }
+ (TyKind::FnPtr(sig, hdr), TyKind::FnPtr(sig2, hdr2)) => sig == sig2 && hdr == hdr2,
+ (TyKind::Tuple(tys), TyKind::Tuple(tys2)) => tys.len() == tys2.len(),
+ (TyKind::Str, TyKind::Str)
+ | (TyKind::Never, TyKind::Never)
+ | (TyKind::Char, TyKind::Char)
+ | (TyKind::Bool, TyKind::Bool) => true,
+ (TyKind::Int(int), TyKind::Int(int2)) => int == int2,
+ (TyKind::Float(float), TyKind::Float(float2)) => float == float2,
+ _ => false,
+ }
+ }
+}
+
+pub fn references_non_lt_error<'db, T: TypeVisitableExt<DbInterner<'db>>>(t: &T) -> bool {
+ t.references_error() && t.visit_with(&mut ReferencesNonLifetimeError).is_break()
+}
+
+struct ReferencesNonLifetimeError;
+
+impl<'db> TypeVisitor<DbInterner<'db>> for ReferencesNonLifetimeError {
+ type Result = ControlFlow<()>;
+
+ fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result {
+ if ty.is_ty_error() { ControlFlow::Break(()) } else { ty.super_visit_with(self) }
+ }
+
+ fn visit_const(&mut self, c: Const<'db>) -> Self::Result {
+ if c.is_ct_error() { ControlFlow::Break(()) } else { c.super_visit_with(self) }
+ }
+}
+
+impl<'db> std::fmt::Debug for Ty<'db> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.inner().internee.fmt(f)
+ }
+}
+
+impl<'db> std::fmt::Debug for InternedWrapperNoDebug<WithCachedTypeInfo<TyKind<'db>>> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.0.internee.fmt(f)
+ }
+}
+
+impl<'db> IntoKind for Ty<'db> {
+ type Kind = TyKind<'db>;
+
+ fn kind(self) -> Self::Kind {
+ self.inner().internee
+ }
+}
+
+impl<'db> TypeVisitable<DbInterner<'db>> for Ty<'db> {
+ fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
+ &self,
+ visitor: &mut V,
+ ) -> V::Result {
+ visitor.visit_ty(*self)
+ }
+}
+
+impl<'db> TypeSuperVisitable<DbInterner<'db>> for Ty<'db> {
+ fn super_visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
+ &self,
+ visitor: &mut V,
+ ) -> V::Result {
+ match (*self).kind() {
+ TyKind::RawPtr(ty, _mutbl) => ty.visit_with(visitor),
+ TyKind::Array(typ, sz) => {
+ try_visit!(typ.visit_with(visitor));
+ sz.visit_with(visitor)
+ }
+ TyKind::Slice(typ) => typ.visit_with(visitor),
+ TyKind::Adt(_, args) => args.visit_with(visitor),
+ TyKind::Dynamic(ref trait_ty, ref reg) => {
+ try_visit!(trait_ty.visit_with(visitor));
+ reg.visit_with(visitor)
+ }
+ TyKind::Tuple(ts) => ts.visit_with(visitor),
+ TyKind::FnDef(_, args) => args.visit_with(visitor),
+ TyKind::FnPtr(ref sig_tys, _) => sig_tys.visit_with(visitor),
+ TyKind::UnsafeBinder(f) => f.visit_with(visitor),
+ TyKind::Ref(r, ty, _) => {
+ try_visit!(r.visit_with(visitor));
+ ty.visit_with(visitor)
+ }
+ TyKind::Coroutine(_did, ref args) => args.visit_with(visitor),
+ TyKind::CoroutineWitness(_did, ref args) => args.visit_with(visitor),
+ TyKind::Closure(_did, ref args) => args.visit_with(visitor),
+ TyKind::CoroutineClosure(_did, ref args) => args.visit_with(visitor),
+ TyKind::Alias(_, ref data) => data.visit_with(visitor),
+
+ TyKind::Pat(ty, pat) => {
+ try_visit!(ty.visit_with(visitor));
+ pat.visit_with(visitor)
+ }
+
+ TyKind::Error(guar) => guar.visit_with(visitor),
+
+ TyKind::Bool
+ | TyKind::Char
+ | TyKind::Str
+ | TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_)
+ | TyKind::Infer(_)
+ | TyKind::Bound(..)
+ | TyKind::Placeholder(..)
+ | TyKind::Param(..)
+ | TyKind::Never
+ | TyKind::Foreign(..) => V::Result::output(),
+ }
+ }
+}
+
+impl<'db> TypeFoldable<DbInterner<'db>> for Ty<'db> {
+ fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ folder.try_fold_ty(self)
+ }
+ fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
+ folder.fold_ty(self)
+ }
+}
+
+impl<'db> TypeSuperFoldable<DbInterner<'db>> for Ty<'db> {
+ fn try_super_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ let kind = match self.kind() {
+ TyKind::RawPtr(ty, mutbl) => TyKind::RawPtr(ty.try_fold_with(folder)?, mutbl),
+ TyKind::Array(typ, sz) => {
+ TyKind::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?)
+ }
+ TyKind::Slice(typ) => TyKind::Slice(typ.try_fold_with(folder)?),
+ TyKind::Adt(tid, args) => TyKind::Adt(tid, args.try_fold_with(folder)?),
+ TyKind::Dynamic(trait_ty, region) => {
+ TyKind::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?)
+ }
+ TyKind::Tuple(ts) => TyKind::Tuple(ts.try_fold_with(folder)?),
+ TyKind::FnDef(def_id, args) => TyKind::FnDef(def_id, args.try_fold_with(folder)?),
+ TyKind::FnPtr(sig_tys, hdr) => TyKind::FnPtr(sig_tys.try_fold_with(folder)?, hdr),
+ TyKind::UnsafeBinder(f) => TyKind::UnsafeBinder(f.try_fold_with(folder)?),
+ TyKind::Ref(r, ty, mutbl) => {
+ TyKind::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl)
+ }
+ TyKind::Coroutine(did, args) => TyKind::Coroutine(did, args.try_fold_with(folder)?),
+ TyKind::CoroutineWitness(did, args) => {
+ TyKind::CoroutineWitness(did, args.try_fold_with(folder)?)
+ }
+ TyKind::Closure(did, args) => TyKind::Closure(did, args.try_fold_with(folder)?),
+ TyKind::CoroutineClosure(did, args) => {
+ TyKind::CoroutineClosure(did, args.try_fold_with(folder)?)
+ }
+ TyKind::Alias(kind, data) => TyKind::Alias(kind, data.try_fold_with(folder)?),
+ TyKind::Pat(ty, pat) => {
+ TyKind::Pat(ty.try_fold_with(folder)?, pat.try_fold_with(folder)?)
+ }
+
+ TyKind::Bool
+ | TyKind::Char
+ | TyKind::Str
+ | TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_)
+ | TyKind::Error(_)
+ | TyKind::Infer(_)
+ | TyKind::Param(..)
+ | TyKind::Bound(..)
+ | TyKind::Placeholder(..)
+ | TyKind::Never
+ | TyKind::Foreign(..) => return Ok(self),
+ };
+
+ Ok(if self.kind() == kind { self } else { Ty::new(folder.cx(), kind) })
+ }
+ fn super_fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(
+ self,
+ folder: &mut F,
+ ) -> Self {
+ let kind = match self.kind() {
+ TyKind::RawPtr(ty, mutbl) => TyKind::RawPtr(ty.fold_with(folder), mutbl),
+ TyKind::Array(typ, sz) => TyKind::Array(typ.fold_with(folder), sz.fold_with(folder)),
+ TyKind::Slice(typ) => TyKind::Slice(typ.fold_with(folder)),
+ TyKind::Adt(tid, args) => TyKind::Adt(tid, args.fold_with(folder)),
+ TyKind::Dynamic(trait_ty, region) => {
+ TyKind::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder))
+ }
+ TyKind::Tuple(ts) => TyKind::Tuple(ts.fold_with(folder)),
+ TyKind::FnDef(def_id, args) => TyKind::FnDef(def_id, args.fold_with(folder)),
+ TyKind::FnPtr(sig_tys, hdr) => TyKind::FnPtr(sig_tys.fold_with(folder), hdr),
+ TyKind::UnsafeBinder(f) => TyKind::UnsafeBinder(f.fold_with(folder)),
+ TyKind::Ref(r, ty, mutbl) => {
+ TyKind::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl)
+ }
+ TyKind::Coroutine(did, args) => TyKind::Coroutine(did, args.fold_with(folder)),
+ TyKind::CoroutineWitness(did, args) => {
+ TyKind::CoroutineWitness(did, args.fold_with(folder))
+ }
+ TyKind::Closure(did, args) => TyKind::Closure(did, args.fold_with(folder)),
+ TyKind::CoroutineClosure(did, args) => {
+ TyKind::CoroutineClosure(did, args.fold_with(folder))
+ }
+ TyKind::Alias(kind, data) => TyKind::Alias(kind, data.fold_with(folder)),
+ TyKind::Pat(ty, pat) => TyKind::Pat(ty.fold_with(folder), pat.fold_with(folder)),
+
+ TyKind::Bool
+ | TyKind::Char
+ | TyKind::Str
+ | TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_)
+ | TyKind::Error(_)
+ | TyKind::Infer(_)
+ | TyKind::Param(..)
+ | TyKind::Bound(..)
+ | TyKind::Placeholder(..)
+ | TyKind::Never
+ | TyKind::Foreign(..) => return self,
+ };
+
+ if self.kind() == kind { self } else { Ty::new(folder.cx(), kind) }
+ }
+}
+
+impl<'db> Relate<DbInterner<'db>> for Ty<'db> {
+ fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
+ relation: &mut R,
+ a: Self,
+ b: Self,
+ ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
+ relation.tys(a, b)
+ }
+}
+
+impl<'db> Flags for Ty<'db> {
+ fn flags(&self) -> rustc_type_ir::TypeFlags {
+ self.inner().flags
+ }
+
+ fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
+ self.inner().outer_exclusive_binder
+ }
+}
+
+impl<'db> rustc_type_ir::inherent::Ty<DbInterner<'db>> for Ty<'db> {
+ fn new_unit(interner: DbInterner<'db>) -> Self {
+ Ty::new(interner, TyKind::Tuple(Default::default()))
+ }
+
+ fn new_bool(interner: DbInterner<'db>) -> Self {
+ Ty::new(interner, TyKind::Bool)
+ }
+
+ fn new_u8(interner: DbInterner<'db>) -> Self {
+ Ty::new(interner, TyKind::Uint(rustc_type_ir::UintTy::U8))
+ }
+
+ fn new_usize(interner: DbInterner<'db>) -> Self {
+ Ty::new(interner, TyKind::Uint(rustc_type_ir::UintTy::Usize))
+ }
+
+ fn new_infer(interner: DbInterner<'db>, var: rustc_type_ir::InferTy) -> Self {
+ Ty::new(interner, TyKind::Infer(var))
+ }
+
+ fn new_var(interner: DbInterner<'db>, var: rustc_type_ir::TyVid) -> Self {
+ Ty::new(interner, TyKind::Infer(rustc_type_ir::InferTy::TyVar(var)))
+ }
+
+ fn new_param(interner: DbInterner<'db>, param: ParamTy) -> Self {
+ Ty::new(interner, TyKind::Param(param))
+ }
+
+ fn new_placeholder(interner: DbInterner<'db>, param: PlaceholderTy) -> Self {
+ Ty::new(interner, TyKind::Placeholder(param))
+ }
+
+ fn new_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundTy) -> Self {
+ Ty::new(interner, TyKind::Bound(BoundVarIndexKind::Bound(debruijn), var))
+ }
+
+ fn new_anon_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundVar) -> Self {
+ Ty::new(
+ interner,
+ TyKind::Bound(
+ BoundVarIndexKind::Bound(debruijn),
+ BoundTy { var, kind: BoundTyKind::Anon },
+ ),
+ )
+ }
+
+ fn new_canonical_bound(interner: DbInterner<'db>, var: BoundVar) -> Self {
+ Ty::new(
+ interner,
+ TyKind::Bound(BoundVarIndexKind::Canonical, BoundTy { var, kind: BoundTyKind::Anon }),
+ )
+ }
+
+ fn new_alias(interner: DbInterner<'db>, kind: AliasTyKind, alias_ty: AliasTy<'db>) -> Self {
+ Ty::new(interner, TyKind::Alias(kind, alias_ty))
+ }
+
+ fn new_error(interner: DbInterner<'db>, guar: ErrorGuaranteed) -> Self {
+ Ty::new(interner, TyKind::Error(guar))
+ }
+
+ fn new_adt(
+ interner: DbInterner<'db>,
+ adt_def: <DbInterner<'db> as Interner>::AdtDef,
+ args: GenericArgs<'db>,
+ ) -> Self {
+ Ty::new(interner, TyKind::Adt(adt_def, args))
+ }
+
+ fn new_foreign(interner: DbInterner<'db>, def_id: TypeAliasIdWrapper) -> Self {
+ Ty::new(interner, TyKind::Foreign(def_id))
+ }
+
+ fn new_dynamic(
+ interner: DbInterner<'db>,
+ preds: <DbInterner<'db> as Interner>::BoundExistentialPredicates,
+ region: <DbInterner<'db> as Interner>::Region,
+ ) -> Self {
+ Ty::new(interner, TyKind::Dynamic(preds, region))
+ }
+
+ fn new_coroutine(
+ interner: DbInterner<'db>,
+ def_id: CoroutineIdWrapper,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
+ ) -> Self {
+ Ty::new(interner, TyKind::Coroutine(def_id, args))
+ }
+
+ fn new_coroutine_closure(
+ interner: DbInterner<'db>,
+ def_id: CoroutineIdWrapper,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
+ ) -> Self {
+ Ty::new(interner, TyKind::CoroutineClosure(def_id, args))
+ }
+
+ fn new_closure(
+ interner: DbInterner<'db>,
+ def_id: ClosureIdWrapper,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
+ ) -> Self {
+ Ty::new(interner, TyKind::Closure(def_id, args))
+ }
+
+ fn new_coroutine_witness(
+ interner: DbInterner<'db>,
+ def_id: CoroutineIdWrapper,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
+ ) -> Self {
+ Ty::new(interner, TyKind::CoroutineWitness(def_id, args))
+ }
+
+ fn new_coroutine_witness_for_coroutine(
+ interner: DbInterner<'db>,
+ def_id: CoroutineIdWrapper,
+ coroutine_args: <DbInterner<'db> as Interner>::GenericArgs,
+ ) -> Self {
+ // HACK: Coroutine witness types are lifetime erased, so they
+ // never reference any lifetime args from the coroutine. We erase
+ // the regions here since we may get into situations where a
+ // coroutine is recursively contained within itself, leading to
+ // witness types that differ by region args. This means that
+ // cycle detection in fulfillment will not kick in, which leads
+ // to unnecessary overflows in async code. See the issue:
+ // <https://github.com/rust-lang/rust/issues/145151>.
+ let coroutine_args = interner.mk_args_from_iter(coroutine_args.iter().map(|arg| {
+ match arg {
+ GenericArg::Ty(_) | GenericArg::Const(_) => arg,
+ GenericArg::Lifetime(_) => {
+ crate::next_solver::Region::new(interner, rustc_type_ir::RegionKind::ReErased)
+ .into()
+ }
+ }
+ }));
+ Ty::new_coroutine_witness(interner, def_id, coroutine_args)
+ }
+
+ fn new_ptr(interner: DbInterner<'db>, ty: Self, mutbl: rustc_ast_ir::Mutability) -> Self {
+ Ty::new(interner, TyKind::RawPtr(ty, mutbl))
+ }
+
+ fn new_ref(
+ interner: DbInterner<'db>,
+ region: <DbInterner<'db> as Interner>::Region,
+ ty: Self,
+ mutbl: rustc_ast_ir::Mutability,
+ ) -> Self {
+ Ty::new(interner, TyKind::Ref(region, ty, mutbl))
+ }
+
+ fn new_array_with_const_len(
+ interner: DbInterner<'db>,
+ ty: Self,
+ len: <DbInterner<'db> as Interner>::Const,
+ ) -> Self {
+ Ty::new(interner, TyKind::Array(ty, len))
+ }
+
+ fn new_slice(interner: DbInterner<'db>, ty: Self) -> Self {
+ Ty::new(interner, TyKind::Slice(ty))
+ }
+
+ fn new_tup(interner: DbInterner<'db>, tys: &[<DbInterner<'db> as Interner>::Ty]) -> Self {
+ Ty::new(interner, TyKind::Tuple(Tys::new_from_iter(interner, tys.iter().cloned())))
+ }
+
+ fn new_tup_from_iter<It, T>(interner: DbInterner<'db>, iter: It) -> T::Output
+ where
+ It: Iterator<Item = T>,
+ T: rustc_type_ir::CollectAndApply<Self, Self>,
+ {
+ T::collect_and_apply(iter, |ts| Ty::new_tup(interner, ts))
+ }
+
+ fn new_fn_def(
+ interner: DbInterner<'db>,
+ def_id: CallableIdWrapper,
+ args: <DbInterner<'db> as Interner>::GenericArgs,
+ ) -> Self {
+ Ty::new(interner, TyKind::FnDef(def_id, args))
+ }
+
+ fn new_fn_ptr(
+ interner: DbInterner<'db>,
+ sig: rustc_type_ir::Binder<DbInterner<'db>, rustc_type_ir::FnSig<DbInterner<'db>>>,
+ ) -> Self {
+ let (sig_tys, header) = sig.split();
+ Ty::new(interner, TyKind::FnPtr(sig_tys, header))
+ }
+
+ fn new_pat(
+ interner: DbInterner<'db>,
+ ty: Self,
+ pat: <DbInterner<'db> as Interner>::Pat,
+ ) -> Self {
+ Ty::new(interner, TyKind::Pat(ty, pat))
+ }
+
+ fn new_unsafe_binder(
+ interner: DbInterner<'db>,
+ ty: rustc_type_ir::Binder<DbInterner<'db>, <DbInterner<'db> as Interner>::Ty>,
+ ) -> Self {
+ Ty::new(interner, TyKind::UnsafeBinder(ty.into()))
+ }
+
+ fn tuple_fields(self) -> <DbInterner<'db> as Interner>::Tys {
+ match self.kind() {
+ TyKind::Tuple(args) => args,
+ _ => panic!("tuple_fields called on non-tuple: {self:?}"),
+ }
+ }
+
+ fn to_opt_closure_kind(self) -> Option<rustc_type_ir::ClosureKind> {
+ match self.kind() {
+ TyKind::Int(int_ty) => match int_ty {
+ IntTy::I8 => Some(ClosureKind::Fn),
+ IntTy::I16 => Some(ClosureKind::FnMut),
+ IntTy::I32 => Some(ClosureKind::FnOnce),
+ _ => unreachable!("cannot convert type `{:?}` to a closure kind", self),
+ },
+
+ // "Bound" types appear in canonical queries when the
+ // closure type is not yet known, and `Placeholder` and `Param`
+ // may be encountered in generic `AsyncFnKindHelper` goals.
+ TyKind::Bound(..) | TyKind::Placeholder(_) | TyKind::Param(_) | TyKind::Infer(_) => {
+ None
+ }
+
+ TyKind::Error(_) => Some(ClosureKind::Fn),
+
+ _ => unreachable!("cannot convert type `{:?}` to a closure kind", self),
+ }
+ }
+
+ fn from_closure_kind(interner: DbInterner<'db>, kind: rustc_type_ir::ClosureKind) -> Self {
+ match kind {
+ ClosureKind::Fn => Ty::new(interner, TyKind::Int(IntTy::I8)),
+ ClosureKind::FnMut => Ty::new(interner, TyKind::Int(IntTy::I16)),
+ ClosureKind::FnOnce => Ty::new(interner, TyKind::Int(IntTy::I32)),
+ }
+ }
+
+ fn from_coroutine_closure_kind(
+ interner: DbInterner<'db>,
+ kind: rustc_type_ir::ClosureKind,
+ ) -> Self {
+ match kind {
+ ClosureKind::Fn | ClosureKind::FnMut => Ty::new(interner, TyKind::Int(IntTy::I16)),
+ ClosureKind::FnOnce => Ty::new(interner, TyKind::Int(IntTy::I32)),
+ }
+ }
+
+ fn has_unsafe_fields(self) -> bool {
+ false
+ }
+
+ fn discriminant_ty(self, interner: DbInterner<'db>) -> <DbInterner<'db> as Interner>::Ty {
+ match self.kind() {
+ TyKind::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(interner),
+ TyKind::Coroutine(_, args) => args.as_coroutine().discr_ty(interner),
+
+ TyKind::Param(_) | TyKind::Alias(..) | TyKind::Infer(InferTy::TyVar(_)) => {
+ /*
+ let assoc_items = tcx.associated_item_def_ids(
+ tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
+ );
+ TyKind::new_projection_from_args(tcx, assoc_items[0], tcx.mk_args(&[self.into()]))
+ */
+ unimplemented!()
+ }
+
+ TyKind::Pat(ty, _) => ty.discriminant_ty(interner),
+
+ TyKind::Bool
+ | TyKind::Char
+ | TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_)
+ | TyKind::Adt(..)
+ | TyKind::Foreign(_)
+ | TyKind::Str
+ | TyKind::Array(..)
+ | TyKind::Slice(_)
+ | TyKind::RawPtr(_, _)
+ | TyKind::Ref(..)
+ | TyKind::FnDef(..)
+ | TyKind::FnPtr(..)
+ | TyKind::Dynamic(..)
+ | TyKind::Closure(..)
+ | TyKind::CoroutineClosure(..)
+ | TyKind::CoroutineWitness(..)
+ | TyKind::Never
+ | TyKind::Tuple(_)
+ | TyKind::Error(_)
+ | TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => {
+ Ty::new(interner, TyKind::Uint(UintTy::U8))
+ }
+
+ TyKind::Bound(..)
+ | TyKind::Placeholder(_)
+ | TyKind::Infer(
+ InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_),
+ ) => {
+ panic!(
+ "`dself.iter().map(|v| v.try_fold_with(folder)).collect::<Result<_, _>>()?iscriminant_ty` applied to unexpected type: {self:?}"
+ )
+ }
+ TyKind::UnsafeBinder(..) => unimplemented!(),
+ }
+ }
+}
+
+interned_vec_db!(Tys, Ty);
+
+impl<'db> Tys<'db> {
+ pub fn inputs(&self) -> &[Ty<'db>] {
+ self.as_slice().split_last().unwrap().1
+ }
+}
+
+impl<'db> rustc_type_ir::inherent::Tys<DbInterner<'db>> for Tys<'db> {
+ fn inputs(self) -> <DbInterner<'db> as Interner>::FnInputTys {
+ Tys::new_from_iter(
+ DbInterner::conjure(),
+ self.as_slice().split_last().unwrap().1.iter().copied(),
+ )
+ }
+
+ fn output(self) -> <DbInterner<'db> as Interner>::Ty {
+ *self.as_slice().split_last().unwrap().0
+ }
+}
+
+pub type PlaceholderTy = Placeholder<BoundTy>;
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct ParamTy {
+ // FIXME: I'm not pleased with this. Ideally a `Param` should only know its index - the defining item
+ // is known from the `EarlyBinder`. This should also be beneficial for memory usage. But code currently
+ // assumes it can get the definition from `Param` alone - so that's what we got.
+ pub id: TypeParamId,
+ pub index: u32,
+}
+
+impl ParamTy {
+ pub fn to_ty<'db>(self, interner: DbInterner<'db>) -> Ty<'db> {
+ Ty::new_param(interner, self.id, self.index)
+ }
+}
+
+impl std::fmt::Debug for ParamTy {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "#{}", self.index)
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct BoundTy {
+ pub var: BoundVar,
+ // FIXME: This is for diagnostics in rustc, do we really need it?
+ pub kind: BoundTyKind,
+}
+
+impl std::fmt::Debug for BoundTy {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self.kind {
+ BoundTyKind::Anon => write!(f, "{:?}", self.var),
+ BoundTyKind::Param(def_id) => write!(f, "{def_id:?}"),
+ }
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum BoundTyKind {
+ Anon,
+ Param(SolverDefId),
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct ErrorGuaranteed;
+
+impl<'db> TypeVisitable<DbInterner<'db>> for ErrorGuaranteed {
+ fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
+ &self,
+ visitor: &mut V,
+ ) -> V::Result {
+ visitor.visit_error(*self)
+ }
+}
+
+impl<'db> TypeFoldable<DbInterner<'db>> for ErrorGuaranteed {
+ fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+ fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, _folder: &mut F) -> Self {
+ self
+ }
+}
+
+impl ParamLike for ParamTy {
+ fn index(self) -> u32 {
+ self.index
+ }
+}
+
+impl<'db> BoundVarLike<DbInterner<'db>> for BoundTy {
+ fn var(self) -> BoundVar {
+ self.var
+ }
+
+ fn assert_eq(self, var: BoundVarKind) {
+ assert_eq!(self.kind, var.expect_ty())
+ }
+}
+
+impl<'db> PlaceholderLike<DbInterner<'db>> for PlaceholderTy {
+ type Bound = BoundTy;
+
+ fn universe(self) -> rustc_type_ir::UniverseIndex {
+ self.universe
+ }
+
+ fn var(self) -> BoundVar {
+ self.bound.var
+ }
+
+ fn with_updated_universe(self, ui: rustc_type_ir::UniverseIndex) -> Self {
+ Placeholder { universe: ui, bound: self.bound }
+ }
+
+ fn new(ui: rustc_type_ir::UniverseIndex, bound: BoundTy) -> Self {
+ Placeholder { universe: ui, bound }
+ }
+
+ fn new_anon(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self {
+ Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } }
+ }
+}