mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-25 11:17:13 +00:00

fallback.rs was ported straight from rustc (minus the lint parts). This fixes the `!` regressions.
1054 lines
37 KiB
Rust
1054 lines
37 KiB
Rust
//! Things related to tys in the next-trait-solver.
|
|
|
|
use std::iter;
|
|
use std::ops::ControlFlow;
|
|
|
|
use hir_def::{GenericDefId, TypeOrConstParamId, TypeParamId};
|
|
use intern::{Interned, Symbol, sym};
|
|
use rustc_abi::{Float, Integer, Size};
|
|
use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult};
|
|
use rustc_type_ir::TyVid;
|
|
use rustc_type_ir::{
|
|
BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, InferTy,
|
|
IntTy, IntVid, Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
|
|
TypeVisitableExt, TypeVisitor, UintTy, WithCachedTypeInfo,
|
|
inherent::{
|
|
Abi, AdtDef, BoundVarLike, Const as _, GenericArgs as _, IntoKind, ParamLike,
|
|
PlaceholderLike, Safety as _, SliceLike, Ty as _,
|
|
},
|
|
relate::Relate,
|
|
solve::SizedTraitKind,
|
|
walk::TypeWalker,
|
|
};
|
|
use salsa::plumbing::{AsId, FromId};
|
|
use smallvec::SmallVec;
|
|
|
|
use crate::{
|
|
FnAbi,
|
|
db::HirDatabase,
|
|
interner::InternedWrapperNoDebug,
|
|
next_solver::{
|
|
CallableIdWrapper, ClosureIdWrapper, Const, CoroutineIdWrapper, FnSig, GenericArg,
|
|
PolyFnSig, TypeAliasIdWrapper,
|
|
abi::Safety,
|
|
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,
|
|
#[cfg(feature = "in-rust-tree")]
|
|
stable_hash: ena::fingerprint::Fingerprint::ZERO,
|
|
};
|
|
Ty::new_(interner.db(), InternedWrapperNoDebug(cached))
|
|
}
|
|
|
|
pub fn inner(&self) -> &WithCachedTypeInfo<TyKind<'db>> {
|
|
salsa::with_attached_database(|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) }
|
|
})
|
|
.unwrap()
|
|
}
|
|
|
|
pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32, name: Symbol) -> 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 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 {
|
|
self.references_error() && self.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: rustc_type_ir::DebruijnIndex,
|
|
var: BoundTy,
|
|
) -> Self {
|
|
Ty::new(interner, TyKind::Bound(debruijn, var))
|
|
}
|
|
|
|
fn new_anon_bound(
|
|
interner: DbInterner<'db>,
|
|
debruijn: rustc_type_ir::DebruijnIndex,
|
|
var: BoundVar,
|
|
) -> Self {
|
|
Ty::new(interner, TyKind::Bound(debruijn, BoundTy { var, kind: BoundTyKind::Anon }))
|
|
}
|
|
|
|
fn new_alias(
|
|
interner: DbInterner<'db>,
|
|
kind: rustc_type_ir::AliasTyKind,
|
|
alias_ty: rustc_type_ir::AliasTy<DbInterner<'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 rustc_type_ir::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 rustc_type_ir::Interner>::BoundExistentialPredicates,
|
|
region: <DbInterner<'db> as rustc_type_ir::Interner>::Region,
|
|
) -> Self {
|
|
Ty::new(interner, TyKind::Dynamic(preds, region))
|
|
}
|
|
|
|
fn new_coroutine(
|
|
interner: DbInterner<'db>,
|
|
def_id: CoroutineIdWrapper,
|
|
args: <DbInterner<'db> as rustc_type_ir::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 rustc_type_ir::Interner>::GenericArgs,
|
|
) -> Self {
|
|
Ty::new(interner, TyKind::CoroutineClosure(def_id, args))
|
|
}
|
|
|
|
fn new_closure(
|
|
interner: DbInterner<'db>,
|
|
def_id: ClosureIdWrapper,
|
|
args: <DbInterner<'db> as rustc_type_ir::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 rustc_type_ir::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 rustc_type_ir::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 rustc_type_ir::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 rustc_type_ir::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 rustc_type_ir::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 rustc_type_ir::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 rustc_type_ir::Interner>::Pat,
|
|
) -> Self {
|
|
Ty::new(interner, TyKind::Pat(ty, pat))
|
|
}
|
|
|
|
fn tuple_fields(self) -> <DbInterner<'db> as rustc_type_ir::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 discriminant_ty(
|
|
self,
|
|
interner: DbInterner<'db>,
|
|
) -> <DbInterner<'db> as rustc_type_ir::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!(),
|
|
}
|
|
}
|
|
|
|
fn new_unsafe_binder(
|
|
interner: DbInterner<'db>,
|
|
ty: rustc_type_ir::Binder<
|
|
DbInterner<'db>,
|
|
<DbInterner<'db> as rustc_type_ir::Interner>::Ty,
|
|
>,
|
|
) -> Self {
|
|
Ty::new(interner, TyKind::UnsafeBinder(ty.into()))
|
|
}
|
|
|
|
fn has_unsafe_fields(self) -> bool {
|
|
false
|
|
}
|
|
}
|
|
|
|
interned_vec_db!(Tys, Ty);
|
|
|
|
impl<'db> rustc_type_ir::inherent::Tys<DbInterner<'db>> for Tys<'db> {
|
|
fn inputs(self) -> <DbInterner<'db> as rustc_type_ir::Interner>::FnInputTys {
|
|
Tys::new_from_iter(
|
|
DbInterner::conjure(),
|
|
self.as_slice().split_last().unwrap().1.iter().cloned(),
|
|
)
|
|
}
|
|
|
|
fn output(self) -> <DbInterner<'db> as rustc_type_ir::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, sym::MISSING_NAME.clone())
|
|
}
|
|
}
|
|
|
|
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 } }
|
|
}
|
|
}
|