mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
Auto merge of #116951 - compiler-errors:ir-file-structure, r=jackh726
Restructure `rustc_type_ir` a bit 1. Split `sty` into new `ty_kind`/`region_kind`/`const_kind` modules, so that when we uplift more kinds (e.g. `PredicateKind`, `ClauseKind`, and `ExistentialPredicate`), they can live in their own simple-to-understand files. 2. Split up the `structural_impls` module, which is a kitchen sink of random impls -- move `TypeFoldable` and `TypeVisitable` impls into existing `fold` and `visit` modules, respectively. 3. Move the `DebugWithInfcx` trait and blanket impls into a new `debug` module, and `TypeFlags` definition into a new `flags` module. 5. Move `Interner` trait into a new `interner` module. I expect this file to get a lot larger as we make the interner more powerful for the trait solver refactor. r? `@ghost` for now, will assign once #116946 lands
This commit is contained in:
commit
96027d945b
@ -8,7 +8,7 @@ use rustc_middle::ty::adjustment::PointerCoercion;
|
|||||||
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
|
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
|
||||||
use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
|
use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
|
||||||
use rustc_target::abi::Integer;
|
use rustc_target::abi::Integer;
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy,
|
util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy,
|
||||||
@ -185,7 +185,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
src: &ImmTy<'tcx, M::Provenance>,
|
src: &ImmTy<'tcx, M::Provenance>,
|
||||||
cast_to: TyAndLayout<'tcx>,
|
cast_to: TyAndLayout<'tcx>,
|
||||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
|
|
||||||
let val = match src.layout.ty.kind() {
|
let val = match src.layout.ty.kind() {
|
||||||
// Floating point
|
// Floating point
|
||||||
@ -310,7 +310,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
where
|
where
|
||||||
F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
|
F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
|
||||||
{
|
{
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
|
|
||||||
fn adjust_nan<
|
fn adjust_nan<
|
||||||
'mir,
|
'mir,
|
||||||
|
@ -162,7 +162,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
|
|||||||
// trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
|
// trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
|
||||||
// in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
|
// in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
|
||||||
// even if they do not carry that attribute.
|
// even if they do not carry that attribute.
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
match (source.kind(), target.kind()) {
|
match (source.kind(), target.kind()) {
|
||||||
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
|
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
|
||||||
if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
|
if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
|
||||||
|
@ -20,7 +20,7 @@ use rustc_span::Span;
|
|||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
|
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
|
use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
/// Checks a `a <op>= b`
|
/// Checks a `a <op>= b`
|
||||||
|
@ -2475,7 +2475,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
|||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
init: InitKind,
|
init: InitKind,
|
||||||
) -> Option<InitError> {
|
) -> Option<InitError> {
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
// Primitive types that don't like 0 as a value.
|
// Primitive types that don't like 0 as a value.
|
||||||
Ref(..) => Some("references must be non-null".into()),
|
Ref(..) => Some("references must be non-null".into()),
|
||||||
|
@ -262,7 +262,7 @@ fn structurally_same_type_impl<'tcx>(
|
|||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
// Do a full, depth-first comparison between the two.
|
// Do a full, depth-first comparison between the two.
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
let a_kind = a.kind();
|
let a_kind = a.kind();
|
||||||
let b_kind = b.kind();
|
let b_kind = b.kind();
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
|||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
|
use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
use rustc_type_ir::WithCachedTypeInfo;
|
use rustc_type_ir::WithCachedTypeInfo;
|
||||||
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
|
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ use rustc_hir::def::DefKind;
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{PredicateOrigin, WherePredicate};
|
use rustc_hir::{PredicateOrigin, WherePredicate};
|
||||||
use rustc_span::{BytePos, Span};
|
use rustc_span::{BytePos, Span};
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
|
|
||||||
impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
|
impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
|
||||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||||
|
@ -47,7 +47,7 @@ use crate::query::Providers;
|
|||||||
use crate::ty::context::TyCtxt;
|
use crate::ty::context::TyCtxt;
|
||||||
use crate::ty::{self, DefId, Ty, VariantDef, Visibility};
|
use crate::ty::{self, DefId, Ty, VariantDef, Visibility};
|
||||||
|
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
|
|
||||||
pub mod inhabited_predicate;
|
pub mod inhabited_predicate;
|
||||||
|
|
||||||
|
@ -33,13 +33,13 @@ use std::marker::PhantomData;
|
|||||||
use std::ops::{ControlFlow, Deref, Range};
|
use std::ops::{ControlFlow, Deref, Range};
|
||||||
use ty::util::IntTypeExt;
|
use ty::util::IntTypeExt;
|
||||||
|
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
|
||||||
use rustc_type_ir::CollectAndApply;
|
use rustc_type_ir::CollectAndApply;
|
||||||
use rustc_type_ir::ConstKind as IrConstKind;
|
use rustc_type_ir::ConstKind as IrConstKind;
|
||||||
use rustc_type_ir::DebugWithInfcx;
|
use rustc_type_ir::DebugWithInfcx;
|
||||||
use rustc_type_ir::DynKind;
|
use rustc_type_ir::DynKind;
|
||||||
use rustc_type_ir::RegionKind as IrRegionKind;
|
use rustc_type_ir::RegionKind as IrRegionKind;
|
||||||
use rustc_type_ir::TyKind as IrTyKind;
|
use rustc_type_ir::TyKind as IrTyKind;
|
||||||
|
use rustc_type_ir::TyKind::*;
|
||||||
|
|
||||||
use super::GenericParamDefKind;
|
use super::GenericParamDefKind;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ fn sized_constraint_for_ty<'tcx>(
|
|||||||
adtdef: ty::AdtDef<'tcx>,
|
adtdef: ty::AdtDef<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Vec<Ty<'tcx>> {
|
) -> Vec<Ty<'tcx>> {
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
|
|
||||||
let result = match ty.kind() {
|
let result = match ty.kind() {
|
||||||
Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
|
Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
|
||||||
|
258
compiler/rustc_type_ir/src/const_kind.rs
Normal file
258
compiler/rustc_type_ir/src/const_kind.rs
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
use rustc_data_structures::stable_hasher::HashStable;
|
||||||
|
use rustc_serialize::{Decodable, Decoder, Encodable};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt;
|
||||||
|
use std::hash;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx,
|
||||||
|
TyDecoder, TyEncoder,
|
||||||
|
};
|
||||||
|
|
||||||
|
use self::ConstKind::*;
|
||||||
|
|
||||||
|
/// Represents a constant in Rust.
|
||||||
|
// #[derive(derive_more::From)]
|
||||||
|
pub enum ConstKind<I: Interner> {
|
||||||
|
/// A const generic parameter.
|
||||||
|
Param(I::ParamConst),
|
||||||
|
|
||||||
|
/// Infer the value of the const.
|
||||||
|
Infer(I::InferConst),
|
||||||
|
|
||||||
|
/// Bound const variable, used only when preparing a trait query.
|
||||||
|
Bound(DebruijnIndex, I::BoundConst),
|
||||||
|
|
||||||
|
/// A placeholder const - universally quantified higher-ranked const.
|
||||||
|
Placeholder(I::PlaceholderConst),
|
||||||
|
|
||||||
|
/// An unnormalized const item such as an anon const or assoc const or free const item.
|
||||||
|
/// Right now anything other than anon consts does not actually work properly but this
|
||||||
|
/// should
|
||||||
|
Unevaluated(I::AliasConst),
|
||||||
|
|
||||||
|
/// Used to hold computed value.
|
||||||
|
Value(I::ValueConst),
|
||||||
|
|
||||||
|
/// A placeholder for a const which could not be computed; this is
|
||||||
|
/// propagated to avoid useless error messages.
|
||||||
|
Error(I::ErrorGuaranteed),
|
||||||
|
|
||||||
|
/// Unevaluated non-const-item, used by `feature(generic_const_exprs)` to represent
|
||||||
|
/// const arguments such as `N + 1` or `foo(N)`
|
||||||
|
Expr(I::ExprConst),
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn const_kind_discriminant<I: Interner>(value: &ConstKind<I>) -> usize {
|
||||||
|
match value {
|
||||||
|
Param(_) => 0,
|
||||||
|
Infer(_) => 1,
|
||||||
|
Bound(_, _) => 2,
|
||||||
|
Placeholder(_) => 3,
|
||||||
|
Unevaluated(_) => 4,
|
||||||
|
Value(_) => 5,
|
||||||
|
Error(_) => 6,
|
||||||
|
Expr(_) => 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> hash::Hash for ConstKind<I> {
|
||||||
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||||
|
const_kind_discriminant(self).hash(state);
|
||||||
|
match self {
|
||||||
|
Param(p) => p.hash(state),
|
||||||
|
Infer(i) => i.hash(state),
|
||||||
|
Bound(d, b) => {
|
||||||
|
d.hash(state);
|
||||||
|
b.hash(state);
|
||||||
|
}
|
||||||
|
Placeholder(p) => p.hash(state),
|
||||||
|
Unevaluated(u) => u.hash(state),
|
||||||
|
Value(v) => v.hash(state),
|
||||||
|
Error(e) => e.hash(state),
|
||||||
|
Expr(e) => e.hash(state),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ConstKind<I>
|
||||||
|
where
|
||||||
|
I::ParamConst: HashStable<CTX>,
|
||||||
|
I::InferConst: HashStable<CTX>,
|
||||||
|
I::BoundConst: HashStable<CTX>,
|
||||||
|
I::PlaceholderConst: HashStable<CTX>,
|
||||||
|
I::AliasConst: HashStable<CTX>,
|
||||||
|
I::ValueConst: HashStable<CTX>,
|
||||||
|
I::ErrorGuaranteed: HashStable<CTX>,
|
||||||
|
I::ExprConst: HashStable<CTX>,
|
||||||
|
{
|
||||||
|
fn hash_stable(
|
||||||
|
&self,
|
||||||
|
hcx: &mut CTX,
|
||||||
|
hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
|
||||||
|
) {
|
||||||
|
const_kind_discriminant(self).hash_stable(hcx, hasher);
|
||||||
|
match self {
|
||||||
|
Param(p) => p.hash_stable(hcx, hasher),
|
||||||
|
Infer(i) => i.hash_stable(hcx, hasher),
|
||||||
|
Bound(d, b) => {
|
||||||
|
d.hash_stable(hcx, hasher);
|
||||||
|
b.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
Placeholder(p) => p.hash_stable(hcx, hasher),
|
||||||
|
Unevaluated(u) => u.hash_stable(hcx, hasher),
|
||||||
|
Value(v) => v.hash_stable(hcx, hasher),
|
||||||
|
Error(e) => e.hash_stable(hcx, hasher),
|
||||||
|
Expr(e) => e.hash_stable(hcx, hasher),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for ConstKind<I>
|
||||||
|
where
|
||||||
|
I::ParamConst: Decodable<D>,
|
||||||
|
I::InferConst: Decodable<D>,
|
||||||
|
I::BoundConst: Decodable<D>,
|
||||||
|
I::PlaceholderConst: Decodable<D>,
|
||||||
|
I::AliasConst: Decodable<D>,
|
||||||
|
I::ValueConst: Decodable<D>,
|
||||||
|
I::ErrorGuaranteed: Decodable<D>,
|
||||||
|
I::ExprConst: Decodable<D>,
|
||||||
|
{
|
||||||
|
fn decode(d: &mut D) -> Self {
|
||||||
|
match Decoder::read_usize(d) {
|
||||||
|
0 => Param(Decodable::decode(d)),
|
||||||
|
1 => Infer(Decodable::decode(d)),
|
||||||
|
2 => Bound(Decodable::decode(d), Decodable::decode(d)),
|
||||||
|
3 => Placeholder(Decodable::decode(d)),
|
||||||
|
4 => Unevaluated(Decodable::decode(d)),
|
||||||
|
5 => Value(Decodable::decode(d)),
|
||||||
|
6 => Error(Decodable::decode(d)),
|
||||||
|
7 => Expr(Decodable::decode(d)),
|
||||||
|
_ => panic!(
|
||||||
|
"{}",
|
||||||
|
format!(
|
||||||
|
"invalid enum variant tag while decoding `{}`, expected 0..{}",
|
||||||
|
"ConstKind", 8,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for ConstKind<I>
|
||||||
|
where
|
||||||
|
I::ParamConst: Encodable<E>,
|
||||||
|
I::InferConst: Encodable<E>,
|
||||||
|
I::BoundConst: Encodable<E>,
|
||||||
|
I::PlaceholderConst: Encodable<E>,
|
||||||
|
I::AliasConst: Encodable<E>,
|
||||||
|
I::ValueConst: Encodable<E>,
|
||||||
|
I::ErrorGuaranteed: Encodable<E>,
|
||||||
|
I::ExprConst: Encodable<E>,
|
||||||
|
{
|
||||||
|
fn encode(&self, e: &mut E) {
|
||||||
|
let disc = const_kind_discriminant(self);
|
||||||
|
match self {
|
||||||
|
Param(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
|
||||||
|
Infer(i) => e.emit_enum_variant(disc, |e| i.encode(e)),
|
||||||
|
Bound(d, b) => e.emit_enum_variant(disc, |e| {
|
||||||
|
d.encode(e);
|
||||||
|
b.encode(e);
|
||||||
|
}),
|
||||||
|
Placeholder(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
|
||||||
|
Unevaluated(u) => e.emit_enum_variant(disc, |e| u.encode(e)),
|
||||||
|
Value(v) => e.emit_enum_variant(disc, |e| v.encode(e)),
|
||||||
|
Error(er) => e.emit_enum_variant(disc, |e| er.encode(e)),
|
||||||
|
Expr(ex) => e.emit_enum_variant(disc, |e| ex.encode(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> PartialOrd for ConstKind<I> {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> Ord for ConstKind<I> {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
const_kind_discriminant(self)
|
||||||
|
.cmp(&const_kind_discriminant(other))
|
||||||
|
.then_with(|| match (self, other) {
|
||||||
|
(Param(p1), Param(p2)) => p1.cmp(p2),
|
||||||
|
(Infer(i1), Infer(i2)) => i1.cmp(i2),
|
||||||
|
(Bound(d1, b1), Bound(d2, b2)) => d1.cmp(d2).then_with(|| b1.cmp(b2)),
|
||||||
|
(Placeholder(p1), Placeholder(p2)) => p1.cmp(p2),
|
||||||
|
(Unevaluated(u1), Unevaluated(u2)) => u1.cmp(u2),
|
||||||
|
(Value(v1), Value(v2)) => v1.cmp(v2),
|
||||||
|
(Error(e1), Error(e2)) => e1.cmp(e2),
|
||||||
|
(Expr(e1), Expr(e2)) => e1.cmp(e2),
|
||||||
|
_ => {
|
||||||
|
debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}");
|
||||||
|
Ordering::Equal
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> PartialEq for ConstKind<I> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Param(l0), Param(r0)) => l0 == r0,
|
||||||
|
(Infer(l0), Infer(r0)) => l0 == r0,
|
||||||
|
(Bound(l0, l1), Bound(r0, r1)) => l0 == r0 && l1 == r1,
|
||||||
|
(Placeholder(l0), Placeholder(r0)) => l0 == r0,
|
||||||
|
(Unevaluated(l0), Unevaluated(r0)) => l0 == r0,
|
||||||
|
(Value(l0), Value(r0)) => l0 == r0,
|
||||||
|
(Error(l0), Error(r0)) => l0 == r0,
|
||||||
|
(Expr(l0), Expr(r0)) => l0 == r0,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> Eq for ConstKind<I> {}
|
||||||
|
|
||||||
|
impl<I: Interner> Clone for ConstKind<I> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Param(arg0) => Param(arg0.clone()),
|
||||||
|
Infer(arg0) => Infer(arg0.clone()),
|
||||||
|
Bound(arg0, arg1) => Bound(arg0.clone(), arg1.clone()),
|
||||||
|
Placeholder(arg0) => Placeholder(arg0.clone()),
|
||||||
|
Unevaluated(arg0) => Unevaluated(arg0.clone()),
|
||||||
|
Value(arg0) => Value(arg0.clone()),
|
||||||
|
Error(arg0) => Error(arg0.clone()),
|
||||||
|
Expr(arg0) => Expr(arg0.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> fmt::Debug for ConstKind<I> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
use ConstKind::*;
|
||||||
|
|
||||||
|
match this.data {
|
||||||
|
Param(param) => write!(f, "{param:?}"),
|
||||||
|
Infer(var) => write!(f, "{:?}", &this.wrap(var)),
|
||||||
|
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()),
|
||||||
|
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||||
|
Unevaluated(uv) => {
|
||||||
|
write!(f, "{:?}", &this.wrap(uv))
|
||||||
|
}
|
||||||
|
Value(valtree) => write!(f, "{valtree:?}"),
|
||||||
|
Error(_) => write!(f, "{{const error}}"),
|
||||||
|
Expr(expr) => write!(f, "{:?}", &this.wrap(expr)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
117
compiler/rustc_type_ir/src/debug.rs
Normal file
117
compiler/rustc_type_ir/src/debug.rs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
use crate::{Interner, UniverseIndex};
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub trait InferCtxtLike<I: Interner> {
|
||||||
|
fn universe_of_ty(&self, ty: I::InferTy) -> Option<UniverseIndex>;
|
||||||
|
|
||||||
|
fn universe_of_lt(&self, lt: I::InferRegion) -> Option<UniverseIndex>;
|
||||||
|
|
||||||
|
fn universe_of_ct(&self, ct: I::InferConst) -> Option<UniverseIndex>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> InferCtxtLike<I> for core::convert::Infallible {
|
||||||
|
fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn universe_of_lt(&self, _lt: <I as Interner>::InferRegion) -> Option<UniverseIndex> {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DebugWithInfcx<I: Interner>: fmt::Debug {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
) -> fmt::Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
<T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
match f.alternate() {
|
||||||
|
true => {
|
||||||
|
write!(f, "[\n")?;
|
||||||
|
for element in this.data.iter() {
|
||||||
|
write!(f, "{:?},\n", &this.wrap(element))?;
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
write!(f, "[")?;
|
||||||
|
if this.data.len() > 0 {
|
||||||
|
for element in &this.data[..(this.data.len() - 1)] {
|
||||||
|
write!(f, "{:?}, ", &this.wrap(element))?;
|
||||||
|
}
|
||||||
|
if let Some(element) = this.data.last() {
|
||||||
|
write!(f, "{:?}", &this.wrap(element))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OptWithInfcx<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> {
|
||||||
|
pub data: T,
|
||||||
|
pub infcx: Option<&'a InfCtx>,
|
||||||
|
_interner: PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Copy> Copy for OptWithInfcx<'_, I, InfCtx, T> {}
|
||||||
|
|
||||||
|
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Clone> Clone for OptWithInfcx<'_, I, InfCtx, T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { data: self.data.clone(), infcx: self.infcx, _interner: self._interner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I: Interner, T> OptWithInfcx<'a, I, core::convert::Infallible, T> {
|
||||||
|
pub fn new_no_ctx(data: T) -> Self {
|
||||||
|
Self { data, infcx: None, _interner: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> OptWithInfcx<'a, I, InfCtx, T> {
|
||||||
|
pub fn new(data: T, infcx: &'a InfCtx) -> Self {
|
||||||
|
Self { data, infcx: Some(infcx), _interner: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap<U>(self, u: U) -> OptWithInfcx<'a, I, InfCtx, U> {
|
||||||
|
OptWithInfcx { data: u, infcx: self.infcx, _interner: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptWithInfcx<'a, I, InfCtx, U> {
|
||||||
|
OptWithInfcx { data: f(self.data), infcx: self.infcx, _interner: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ref(&self) -> OptWithInfcx<'a, I, InfCtx, &T> {
|
||||||
|
OptWithInfcx { data: &self.data, infcx: self.infcx, _interner: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: DebugWithInfcx<I>> fmt::Debug
|
||||||
|
for OptWithInfcx<'_, I, InfCtx, T>
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
DebugWithInfcx::fmt(self.as_ref(), f)
|
||||||
|
}
|
||||||
|
}
|
119
compiler/rustc_type_ir/src/flags.rs
Normal file
119
compiler/rustc_type_ir/src/flags.rs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
bitflags! {
|
||||||
|
/// Flags that we track on types. These flags are propagated upwards
|
||||||
|
/// through the type during type construction, so that we can quickly check
|
||||||
|
/// whether the type has various kinds of types in it without recursing
|
||||||
|
/// over the type itself.
|
||||||
|
pub struct TypeFlags: u32 {
|
||||||
|
// Does this have parameters? Used to determine whether substitution is
|
||||||
|
// required.
|
||||||
|
/// Does this have `Param`?
|
||||||
|
const HAS_TY_PARAM = 1 << 0;
|
||||||
|
/// Does this have `ReEarlyBound`?
|
||||||
|
const HAS_RE_PARAM = 1 << 1;
|
||||||
|
/// Does this have `ConstKind::Param`?
|
||||||
|
const HAS_CT_PARAM = 1 << 2;
|
||||||
|
|
||||||
|
const HAS_PARAM = TypeFlags::HAS_TY_PARAM.bits
|
||||||
|
| TypeFlags::HAS_RE_PARAM.bits
|
||||||
|
| TypeFlags::HAS_CT_PARAM.bits;
|
||||||
|
|
||||||
|
/// Does this have `Infer`?
|
||||||
|
const HAS_TY_INFER = 1 << 3;
|
||||||
|
/// Does this have `ReVar`?
|
||||||
|
const HAS_RE_INFER = 1 << 4;
|
||||||
|
/// Does this have `ConstKind::Infer`?
|
||||||
|
const HAS_CT_INFER = 1 << 5;
|
||||||
|
|
||||||
|
/// Does this have inference variables? Used to determine whether
|
||||||
|
/// inference is required.
|
||||||
|
const HAS_INFER = TypeFlags::HAS_TY_INFER.bits
|
||||||
|
| TypeFlags::HAS_RE_INFER.bits
|
||||||
|
| TypeFlags::HAS_CT_INFER.bits;
|
||||||
|
|
||||||
|
/// Does this have `Placeholder`?
|
||||||
|
const HAS_TY_PLACEHOLDER = 1 << 6;
|
||||||
|
/// Does this have `RePlaceholder`?
|
||||||
|
const HAS_RE_PLACEHOLDER = 1 << 7;
|
||||||
|
/// Does this have `ConstKind::Placeholder`?
|
||||||
|
const HAS_CT_PLACEHOLDER = 1 << 8;
|
||||||
|
|
||||||
|
/// Does this have placeholders?
|
||||||
|
const HAS_PLACEHOLDER = TypeFlags::HAS_TY_PLACEHOLDER.bits
|
||||||
|
| TypeFlags::HAS_RE_PLACEHOLDER.bits
|
||||||
|
| TypeFlags::HAS_CT_PLACEHOLDER.bits;
|
||||||
|
|
||||||
|
/// `true` if there are "names" of regions and so forth
|
||||||
|
/// that are local to a particular fn/inferctxt
|
||||||
|
const HAS_FREE_LOCAL_REGIONS = 1 << 9;
|
||||||
|
|
||||||
|
/// `true` if there are "names" of types and regions and so forth
|
||||||
|
/// that are local to a particular fn
|
||||||
|
const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits
|
||||||
|
| TypeFlags::HAS_CT_PARAM.bits
|
||||||
|
| TypeFlags::HAS_TY_INFER.bits
|
||||||
|
| TypeFlags::HAS_CT_INFER.bits
|
||||||
|
| TypeFlags::HAS_TY_PLACEHOLDER.bits
|
||||||
|
| TypeFlags::HAS_CT_PLACEHOLDER.bits
|
||||||
|
// We consider 'freshened' types and constants
|
||||||
|
// to depend on a particular fn.
|
||||||
|
// The freshening process throws away information,
|
||||||
|
// which can make things unsuitable for use in a global
|
||||||
|
// cache. Note that there is no 'fresh lifetime' flag -
|
||||||
|
// freshening replaces all lifetimes with `ReErased`,
|
||||||
|
// which is different from how types/const are freshened.
|
||||||
|
| TypeFlags::HAS_TY_FRESH.bits
|
||||||
|
| TypeFlags::HAS_CT_FRESH.bits
|
||||||
|
| TypeFlags::HAS_FREE_LOCAL_REGIONS.bits
|
||||||
|
| TypeFlags::HAS_RE_ERASED.bits;
|
||||||
|
|
||||||
|
/// Does this have `Projection`?
|
||||||
|
const HAS_TY_PROJECTION = 1 << 10;
|
||||||
|
/// Does this have `Inherent`?
|
||||||
|
const HAS_TY_INHERENT = 1 << 11;
|
||||||
|
/// Does this have `Opaque`?
|
||||||
|
const HAS_TY_OPAQUE = 1 << 12;
|
||||||
|
/// Does this have `ConstKind::Unevaluated`?
|
||||||
|
const HAS_CT_PROJECTION = 1 << 13;
|
||||||
|
|
||||||
|
/// Could this type be normalized further?
|
||||||
|
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
|
||||||
|
| TypeFlags::HAS_TY_OPAQUE.bits
|
||||||
|
| TypeFlags::HAS_TY_INHERENT.bits
|
||||||
|
| TypeFlags::HAS_CT_PROJECTION.bits;
|
||||||
|
|
||||||
|
/// Is an error type/const reachable?
|
||||||
|
const HAS_ERROR = 1 << 14;
|
||||||
|
|
||||||
|
/// Does this have any region that "appears free" in the type?
|
||||||
|
/// Basically anything but `ReLateBound` and `ReErased`.
|
||||||
|
const HAS_FREE_REGIONS = 1 << 15;
|
||||||
|
|
||||||
|
/// Does this have any `ReLateBound` regions?
|
||||||
|
const HAS_RE_LATE_BOUND = 1 << 16;
|
||||||
|
/// Does this have any `Bound` types?
|
||||||
|
const HAS_TY_LATE_BOUND = 1 << 17;
|
||||||
|
/// Does this have any `ConstKind::Bound` consts?
|
||||||
|
const HAS_CT_LATE_BOUND = 1 << 18;
|
||||||
|
/// Does this have any bound variables?
|
||||||
|
/// Used to check if a global bound is safe to evaluate.
|
||||||
|
const HAS_LATE_BOUND = TypeFlags::HAS_RE_LATE_BOUND.bits
|
||||||
|
| TypeFlags::HAS_TY_LATE_BOUND.bits
|
||||||
|
| TypeFlags::HAS_CT_LATE_BOUND.bits;
|
||||||
|
|
||||||
|
/// Does this have any `ReErased` regions?
|
||||||
|
const HAS_RE_ERASED = 1 << 19;
|
||||||
|
|
||||||
|
/// Does this value have parameters/placeholders/inference variables which could be
|
||||||
|
/// replaced later, in a way that would change the results of `impl` specialization?
|
||||||
|
const STILL_FURTHER_SPECIALIZABLE = 1 << 20;
|
||||||
|
|
||||||
|
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
|
||||||
|
const HAS_TY_FRESH = 1 << 21;
|
||||||
|
|
||||||
|
/// Does this value have `InferConst::Fresh`?
|
||||||
|
const HAS_CT_FRESH = 1 << 22;
|
||||||
|
|
||||||
|
/// Does this have `Generator` or `GeneratorWitness`?
|
||||||
|
const HAS_TY_GENERATOR = 1 << 23;
|
||||||
|
}
|
||||||
|
}
|
@ -44,6 +44,11 @@
|
|||||||
//! - ty.super_fold_with(folder)
|
//! - ty.super_fold_with(folder)
|
||||||
//! - u.fold_with(folder)
|
//! - u.fold_with(folder)
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
use rustc_index::{Idx, IndexVec};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use crate::{visit::TypeVisitable, Interner};
|
use crate::{visit::TypeVisitable, Interner};
|
||||||
|
|
||||||
/// This trait is implemented for every type that can be folded,
|
/// This trait is implemented for every type that can be folded,
|
||||||
@ -242,3 +247,101 @@ where
|
|||||||
Ok(self.fold_predicate(p))
|
Ok(self.fold_predicate(p))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Traversal implementations.
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeFoldable<I>, U: TypeFoldable<I>> TypeFoldable<I> for (T, U) {
|
||||||
|
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
|
||||||
|
Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, A: TypeFoldable<I>, B: TypeFoldable<I>, C: TypeFoldable<I>> TypeFoldable<I>
|
||||||
|
for (A, B, C)
|
||||||
|
{
|
||||||
|
fn try_fold_with<F: FallibleTypeFolder<I>>(
|
||||||
|
self,
|
||||||
|
folder: &mut F,
|
||||||
|
) -> Result<(A, B, C), F::Error> {
|
||||||
|
Ok((
|
||||||
|
self.0.try_fold_with(folder)?,
|
||||||
|
self.1.try_fold_with(folder)?,
|
||||||
|
self.2.try_fold_with(folder)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Option<T> {
|
||||||
|
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
||||||
|
Ok(match self {
|
||||||
|
Some(v) => Some(v.try_fold_with(folder)?),
|
||||||
|
None => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>> TypeFoldable<I> for Result<T, E> {
|
||||||
|
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
||||||
|
Ok(match self {
|
||||||
|
Ok(v) => Ok(v.try_fold_with(folder)?),
|
||||||
|
Err(e) => Err(e.try_fold_with(folder)?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Lrc<T> {
|
||||||
|
fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
|
||||||
|
// We merely want to replace the contained `T`, if at all possible,
|
||||||
|
// so that we don't needlessly allocate a new `Lrc` or indeed clone
|
||||||
|
// the contained type.
|
||||||
|
unsafe {
|
||||||
|
// First step is to ensure that we have a unique reference to
|
||||||
|
// the contained type, which `Lrc::make_mut` will accomplish (by
|
||||||
|
// allocating a new `Lrc` and cloning the `T` only if required).
|
||||||
|
// This is done *before* casting to `Lrc<ManuallyDrop<T>>` so that
|
||||||
|
// panicking during `make_mut` does not leak the `T`.
|
||||||
|
Lrc::make_mut(&mut self);
|
||||||
|
|
||||||
|
// Casting to `Lrc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
|
||||||
|
// is `repr(transparent)`.
|
||||||
|
let ptr = Lrc::into_raw(self).cast::<mem::ManuallyDrop<T>>();
|
||||||
|
let mut unique = Lrc::from_raw(ptr);
|
||||||
|
|
||||||
|
// Call to `Lrc::make_mut` above guarantees that `unique` is the
|
||||||
|
// sole reference to the contained value, so we can avoid doing
|
||||||
|
// a checked `get_mut` here.
|
||||||
|
let slot = Lrc::get_mut_unchecked(&mut unique);
|
||||||
|
|
||||||
|
// Semantically move the contained type out from `unique`, fold
|
||||||
|
// it, then move the folded value back into `unique`. Should
|
||||||
|
// folding fail, `ManuallyDrop` ensures that the "moved-out"
|
||||||
|
// value is not re-dropped.
|
||||||
|
let owned = mem::ManuallyDrop::take(slot);
|
||||||
|
let folded = owned.try_fold_with(folder)?;
|
||||||
|
*slot = mem::ManuallyDrop::new(folded);
|
||||||
|
|
||||||
|
// Cast back to `Lrc<T>`.
|
||||||
|
Ok(Lrc::from_raw(Lrc::into_raw(unique).cast()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<T> {
|
||||||
|
fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
|
||||||
|
*self = (*self).try_fold_with(folder)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> {
|
||||||
|
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
||||||
|
self.into_iter().map(|t| t.try_fold_with(folder)).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, T> {
|
||||||
|
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
||||||
|
self.raw.try_fold_with(folder).map(IndexVec::from_raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
155
compiler/rustc_type_ir/src/interner.rs
Normal file
155
compiler/rustc_type_ir/src/interner.rs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
use smallvec::SmallVec;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use crate::{DebugWithInfcx, Mutability};
|
||||||
|
|
||||||
|
pub trait Interner: Sized {
|
||||||
|
type DefId: Clone + Debug + Hash + Ord;
|
||||||
|
type AdtDef: Clone + Debug + Hash + Ord;
|
||||||
|
|
||||||
|
type GenericArgs: Clone
|
||||||
|
+ DebugWithInfcx<Self>
|
||||||
|
+ Hash
|
||||||
|
+ Ord
|
||||||
|
+ IntoIterator<Item = Self::GenericArg>;
|
||||||
|
type GenericArg: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
|
||||||
|
type Binder<T>;
|
||||||
|
|
||||||
|
// Predicates
|
||||||
|
type Predicate;
|
||||||
|
type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
|
||||||
|
|
||||||
|
type TypeAndMut: Clone + Debug + Hash + Ord;
|
||||||
|
|
||||||
|
// Kinds of tys
|
||||||
|
type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
type Tys: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
|
||||||
|
type AliasTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
type ParamTy: Clone + Debug + Hash + Ord;
|
||||||
|
type BoundTy: Clone + Debug + Hash + Ord;
|
||||||
|
type PlaceholderTy: Clone + Debug + Hash + Ord;
|
||||||
|
type InferTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
|
||||||
|
// Things stored inside of tys
|
||||||
|
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
|
||||||
|
type BoundExistentialPredicates: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
type PolyFnSig: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
type AllocId: Clone + Debug + Hash + Ord;
|
||||||
|
|
||||||
|
// Kinds of consts
|
||||||
|
type Const: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
type InferConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
type AliasConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
type PlaceholderConst: Clone + Debug + Hash + Ord;
|
||||||
|
type ParamConst: Clone + Debug + Hash + Ord;
|
||||||
|
type BoundConst: Clone + Debug + Hash + Ord;
|
||||||
|
type ValueConst: Clone + Debug + Hash + Ord;
|
||||||
|
type ExprConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
|
||||||
|
// Kinds of regions
|
||||||
|
type Region: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
type EarlyBoundRegion: Clone + Debug + Hash + Ord;
|
||||||
|
type BoundRegion: Clone + Debug + Hash + Ord;
|
||||||
|
type FreeRegion: Clone + Debug + Hash + Ord;
|
||||||
|
type InferRegion: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
type PlaceholderRegion: Clone + Debug + Hash + Ord;
|
||||||
|
|
||||||
|
fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
|
||||||
|
/// that produces `T` items. You could combine them with
|
||||||
|
/// `f(&iter.collect::<Vec<_>>())`, but this requires allocating memory for the
|
||||||
|
/// `Vec`.
|
||||||
|
///
|
||||||
|
/// This trait allows for faster implementations, intended for cases where the
|
||||||
|
/// number of items produced by the iterator is small. There is a blanket impl
|
||||||
|
/// for `T` items, but there is also a fallible impl for `Result<T, E>` items.
|
||||||
|
pub trait CollectAndApply<T, R>: Sized {
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
/// Produce a result of type `Self::Output` from `iter`. The result will
|
||||||
|
/// typically be produced by applying `f` on the elements produced by
|
||||||
|
/// `iter`, though this may not happen in some impls, e.g. if an error
|
||||||
|
/// occurred during iteration.
|
||||||
|
fn collect_and_apply<I, F>(iter: I, f: F) -> Self::Output
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Self>,
|
||||||
|
F: FnOnce(&[T]) -> R;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The blanket impl that always collects all elements and applies `f`.
|
||||||
|
impl<T, R> CollectAndApply<T, R> for T {
|
||||||
|
type Output = R;
|
||||||
|
|
||||||
|
/// Equivalent to `f(&iter.collect::<Vec<_>>())`.
|
||||||
|
fn collect_and_apply<I, F>(mut iter: I, f: F) -> R
|
||||||
|
where
|
||||||
|
I: Iterator<Item = T>,
|
||||||
|
F: FnOnce(&[T]) -> R,
|
||||||
|
{
|
||||||
|
// This code is hot enough that it's worth specializing for the most
|
||||||
|
// common length lists, to avoid the overhead of `SmallVec` creation.
|
||||||
|
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
|
||||||
|
// `size_hint` is incorrect a panic will occur via an `unwrap` or an
|
||||||
|
// `assert`.
|
||||||
|
match iter.size_hint() {
|
||||||
|
(0, Some(0)) => {
|
||||||
|
assert!(iter.next().is_none());
|
||||||
|
f(&[])
|
||||||
|
}
|
||||||
|
(1, Some(1)) => {
|
||||||
|
let t0 = iter.next().unwrap();
|
||||||
|
assert!(iter.next().is_none());
|
||||||
|
f(&[t0])
|
||||||
|
}
|
||||||
|
(2, Some(2)) => {
|
||||||
|
let t0 = iter.next().unwrap();
|
||||||
|
let t1 = iter.next().unwrap();
|
||||||
|
assert!(iter.next().is_none());
|
||||||
|
f(&[t0, t1])
|
||||||
|
}
|
||||||
|
_ => f(&iter.collect::<SmallVec<[_; 8]>>()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A fallible impl that will fail, without calling `f`, if there are any
|
||||||
|
/// errors during collection.
|
||||||
|
impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
|
||||||
|
type Output = Result<R, E>;
|
||||||
|
|
||||||
|
/// Equivalent to `Ok(f(&iter.collect::<Result<Vec<_>>>()?))`.
|
||||||
|
fn collect_and_apply<I, F>(mut iter: I, f: F) -> Result<R, E>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Result<T, E>>,
|
||||||
|
F: FnOnce(&[T]) -> R,
|
||||||
|
{
|
||||||
|
// This code is hot enough that it's worth specializing for the most
|
||||||
|
// common length lists, to avoid the overhead of `SmallVec` creation.
|
||||||
|
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
|
||||||
|
// `size_hint` is incorrect a panic will occur via an `unwrap` or an
|
||||||
|
// `assert`, unless a failure happens first, in which case the result
|
||||||
|
// will be an error anyway.
|
||||||
|
Ok(match iter.size_hint() {
|
||||||
|
(0, Some(0)) => {
|
||||||
|
assert!(iter.next().is_none());
|
||||||
|
f(&[])
|
||||||
|
}
|
||||||
|
(1, Some(1)) => {
|
||||||
|
let t0 = iter.next().unwrap()?;
|
||||||
|
assert!(iter.next().is_none());
|
||||||
|
f(&[t0])
|
||||||
|
}
|
||||||
|
(2, Some(2)) => {
|
||||||
|
let t0 = iter.next().unwrap()?;
|
||||||
|
let t1 = iter.next().unwrap()?;
|
||||||
|
assert!(iter.next().is_none());
|
||||||
|
f(&[t0, t1])
|
||||||
|
}
|
||||||
|
_ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -15,302 +15,35 @@ extern crate bitflags;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc_macros;
|
extern crate rustc_macros;
|
||||||
|
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
|
||||||
use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
|
|
||||||
use smallvec::SmallVec;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::mem::discriminant;
|
|
||||||
|
|
||||||
pub mod codec;
|
pub mod codec;
|
||||||
pub mod fold;
|
pub mod fold;
|
||||||
pub mod sty;
|
|
||||||
pub mod ty_info;
|
pub mod ty_info;
|
||||||
|
pub mod ty_kind;
|
||||||
pub mod visit;
|
pub mod visit;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
mod structural_impls;
|
mod const_kind;
|
||||||
|
mod debug;
|
||||||
|
mod flags;
|
||||||
|
mod interner;
|
||||||
|
mod region_kind;
|
||||||
|
|
||||||
pub use codec::*;
|
pub use codec::*;
|
||||||
pub use structural_impls::{DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
pub use const_kind::*;
|
||||||
pub use sty::*;
|
pub use debug::{DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
||||||
|
pub use flags::*;
|
||||||
|
pub use interner::*;
|
||||||
|
pub use region_kind::*;
|
||||||
pub use ty_info::*;
|
pub use ty_info::*;
|
||||||
|
pub use ty_kind::*;
|
||||||
|
|
||||||
/// Needed so we can use #[derive(HashStable_Generic)]
|
/// Needed so we can use #[derive(HashStable_Generic)]
|
||||||
pub trait HashStableContext {}
|
pub trait HashStableContext {}
|
||||||
|
|
||||||
pub trait Interner: Sized {
|
|
||||||
type DefId: Clone + Debug + Hash + Ord;
|
|
||||||
type AdtDef: Clone + Debug + Hash + Ord;
|
|
||||||
|
|
||||||
type GenericArgs: Clone
|
|
||||||
+ DebugWithInfcx<Self>
|
|
||||||
+ Hash
|
|
||||||
+ Ord
|
|
||||||
+ IntoIterator<Item = Self::GenericArg>;
|
|
||||||
type GenericArg: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
|
|
||||||
type Binder<T>;
|
|
||||||
|
|
||||||
// Predicates
|
|
||||||
type Predicate;
|
|
||||||
type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
|
|
||||||
|
|
||||||
type TypeAndMut: Clone + Debug + Hash + Ord;
|
|
||||||
|
|
||||||
// Kinds of tys
|
|
||||||
type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
type Tys: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
|
|
||||||
type AliasTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
type ParamTy: Clone + Debug + Hash + Ord;
|
|
||||||
type BoundTy: Clone + Debug + Hash + Ord;
|
|
||||||
type PlaceholderTy: Clone + Debug + Hash + Ord;
|
|
||||||
type InferTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
|
|
||||||
// Things stored inside of tys
|
|
||||||
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
|
|
||||||
type BoundExistentialPredicates: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
type PolyFnSig: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
type AllocId: Clone + Debug + Hash + Ord;
|
|
||||||
|
|
||||||
// Kinds of consts
|
|
||||||
type Const: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
type InferConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
type AliasConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
type PlaceholderConst: Clone + Debug + Hash + Ord;
|
|
||||||
type ParamConst: Clone + Debug + Hash + Ord;
|
|
||||||
type BoundConst: Clone + Debug + Hash + Ord;
|
|
||||||
type ValueConst: Clone + Debug + Hash + Ord;
|
|
||||||
type ExprConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
|
|
||||||
// Kinds of regions
|
|
||||||
type Region: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
type EarlyBoundRegion: Clone + Debug + Hash + Ord;
|
|
||||||
type BoundRegion: Clone + Debug + Hash + Ord;
|
|
||||||
type FreeRegion: Clone + Debug + Hash + Ord;
|
|
||||||
type InferRegion: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
|
||||||
type PlaceholderRegion: Clone + Debug + Hash + Ord;
|
|
||||||
|
|
||||||
fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
|
|
||||||
/// that produces `T` items. You could combine them with
|
|
||||||
/// `f(&iter.collect::<Vec<_>>())`, but this requires allocating memory for the
|
|
||||||
/// `Vec`.
|
|
||||||
///
|
|
||||||
/// This trait allows for faster implementations, intended for cases where the
|
|
||||||
/// number of items produced by the iterator is small. There is a blanket impl
|
|
||||||
/// for `T` items, but there is also a fallible impl for `Result<T, E>` items.
|
|
||||||
pub trait CollectAndApply<T, R>: Sized {
|
|
||||||
type Output;
|
|
||||||
|
|
||||||
/// Produce a result of type `Self::Output` from `iter`. The result will
|
|
||||||
/// typically be produced by applying `f` on the elements produced by
|
|
||||||
/// `iter`, though this may not happen in some impls, e.g. if an error
|
|
||||||
/// occurred during iteration.
|
|
||||||
fn collect_and_apply<I, F>(iter: I, f: F) -> Self::Output
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Self>,
|
|
||||||
F: FnOnce(&[T]) -> R;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The blanket impl that always collects all elements and applies `f`.
|
|
||||||
impl<T, R> CollectAndApply<T, R> for T {
|
|
||||||
type Output = R;
|
|
||||||
|
|
||||||
/// Equivalent to `f(&iter.collect::<Vec<_>>())`.
|
|
||||||
fn collect_and_apply<I, F>(mut iter: I, f: F) -> R
|
|
||||||
where
|
|
||||||
I: Iterator<Item = T>,
|
|
||||||
F: FnOnce(&[T]) -> R,
|
|
||||||
{
|
|
||||||
// This code is hot enough that it's worth specializing for the most
|
|
||||||
// common length lists, to avoid the overhead of `SmallVec` creation.
|
|
||||||
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
|
|
||||||
// `size_hint` is incorrect a panic will occur via an `unwrap` or an
|
|
||||||
// `assert`.
|
|
||||||
match iter.size_hint() {
|
|
||||||
(0, Some(0)) => {
|
|
||||||
assert!(iter.next().is_none());
|
|
||||||
f(&[])
|
|
||||||
}
|
|
||||||
(1, Some(1)) => {
|
|
||||||
let t0 = iter.next().unwrap();
|
|
||||||
assert!(iter.next().is_none());
|
|
||||||
f(&[t0])
|
|
||||||
}
|
|
||||||
(2, Some(2)) => {
|
|
||||||
let t0 = iter.next().unwrap();
|
|
||||||
let t1 = iter.next().unwrap();
|
|
||||||
assert!(iter.next().is_none());
|
|
||||||
f(&[t0, t1])
|
|
||||||
}
|
|
||||||
_ => f(&iter.collect::<SmallVec<[_; 8]>>()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A fallible impl that will fail, without calling `f`, if there are any
|
|
||||||
/// errors during collection.
|
|
||||||
impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
|
|
||||||
type Output = Result<R, E>;
|
|
||||||
|
|
||||||
/// Equivalent to `Ok(f(&iter.collect::<Result<Vec<_>>>()?))`.
|
|
||||||
fn collect_and_apply<I, F>(mut iter: I, f: F) -> Result<R, E>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Result<T, E>>,
|
|
||||||
F: FnOnce(&[T]) -> R,
|
|
||||||
{
|
|
||||||
// This code is hot enough that it's worth specializing for the most
|
|
||||||
// common length lists, to avoid the overhead of `SmallVec` creation.
|
|
||||||
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
|
|
||||||
// `size_hint` is incorrect a panic will occur via an `unwrap` or an
|
|
||||||
// `assert`, unless a failure happens first, in which case the result
|
|
||||||
// will be an error anyway.
|
|
||||||
Ok(match iter.size_hint() {
|
|
||||||
(0, Some(0)) => {
|
|
||||||
assert!(iter.next().is_none());
|
|
||||||
f(&[])
|
|
||||||
}
|
|
||||||
(1, Some(1)) => {
|
|
||||||
let t0 = iter.next().unwrap()?;
|
|
||||||
assert!(iter.next().is_none());
|
|
||||||
f(&[t0])
|
|
||||||
}
|
|
||||||
(2, Some(2)) => {
|
|
||||||
let t0 = iter.next().unwrap()?;
|
|
||||||
let t1 = iter.next().unwrap()?;
|
|
||||||
assert!(iter.next().is_none());
|
|
||||||
f(&[t0, t1])
|
|
||||||
}
|
|
||||||
_ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
/// Flags that we track on types. These flags are propagated upwards
|
|
||||||
/// through the type during type construction, so that we can quickly check
|
|
||||||
/// whether the type has various kinds of types in it without recursing
|
|
||||||
/// over the type itself.
|
|
||||||
pub struct TypeFlags: u32 {
|
|
||||||
// Does this have parameters? Used to determine whether substitution is
|
|
||||||
// required.
|
|
||||||
/// Does this have `Param`?
|
|
||||||
const HAS_TY_PARAM = 1 << 0;
|
|
||||||
/// Does this have `ReEarlyBound`?
|
|
||||||
const HAS_RE_PARAM = 1 << 1;
|
|
||||||
/// Does this have `ConstKind::Param`?
|
|
||||||
const HAS_CT_PARAM = 1 << 2;
|
|
||||||
|
|
||||||
const HAS_PARAM = TypeFlags::HAS_TY_PARAM.bits
|
|
||||||
| TypeFlags::HAS_RE_PARAM.bits
|
|
||||||
| TypeFlags::HAS_CT_PARAM.bits;
|
|
||||||
|
|
||||||
/// Does this have `Infer`?
|
|
||||||
const HAS_TY_INFER = 1 << 3;
|
|
||||||
/// Does this have `ReVar`?
|
|
||||||
const HAS_RE_INFER = 1 << 4;
|
|
||||||
/// Does this have `ConstKind::Infer`?
|
|
||||||
const HAS_CT_INFER = 1 << 5;
|
|
||||||
|
|
||||||
/// Does this have inference variables? Used to determine whether
|
|
||||||
/// inference is required.
|
|
||||||
const HAS_INFER = TypeFlags::HAS_TY_INFER.bits
|
|
||||||
| TypeFlags::HAS_RE_INFER.bits
|
|
||||||
| TypeFlags::HAS_CT_INFER.bits;
|
|
||||||
|
|
||||||
/// Does this have `Placeholder`?
|
|
||||||
const HAS_TY_PLACEHOLDER = 1 << 6;
|
|
||||||
/// Does this have `RePlaceholder`?
|
|
||||||
const HAS_RE_PLACEHOLDER = 1 << 7;
|
|
||||||
/// Does this have `ConstKind::Placeholder`?
|
|
||||||
const HAS_CT_PLACEHOLDER = 1 << 8;
|
|
||||||
|
|
||||||
/// Does this have placeholders?
|
|
||||||
const HAS_PLACEHOLDER = TypeFlags::HAS_TY_PLACEHOLDER.bits
|
|
||||||
| TypeFlags::HAS_RE_PLACEHOLDER.bits
|
|
||||||
| TypeFlags::HAS_CT_PLACEHOLDER.bits;
|
|
||||||
|
|
||||||
/// `true` if there are "names" of regions and so forth
|
|
||||||
/// that are local to a particular fn/inferctxt
|
|
||||||
const HAS_FREE_LOCAL_REGIONS = 1 << 9;
|
|
||||||
|
|
||||||
/// `true` if there are "names" of types and regions and so forth
|
|
||||||
/// that are local to a particular fn
|
|
||||||
const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits
|
|
||||||
| TypeFlags::HAS_CT_PARAM.bits
|
|
||||||
| TypeFlags::HAS_TY_INFER.bits
|
|
||||||
| TypeFlags::HAS_CT_INFER.bits
|
|
||||||
| TypeFlags::HAS_TY_PLACEHOLDER.bits
|
|
||||||
| TypeFlags::HAS_CT_PLACEHOLDER.bits
|
|
||||||
// We consider 'freshened' types and constants
|
|
||||||
// to depend on a particular fn.
|
|
||||||
// The freshening process throws away information,
|
|
||||||
// which can make things unsuitable for use in a global
|
|
||||||
// cache. Note that there is no 'fresh lifetime' flag -
|
|
||||||
// freshening replaces all lifetimes with `ReErased`,
|
|
||||||
// which is different from how types/const are freshened.
|
|
||||||
| TypeFlags::HAS_TY_FRESH.bits
|
|
||||||
| TypeFlags::HAS_CT_FRESH.bits
|
|
||||||
| TypeFlags::HAS_FREE_LOCAL_REGIONS.bits
|
|
||||||
| TypeFlags::HAS_RE_ERASED.bits;
|
|
||||||
|
|
||||||
/// Does this have `Projection`?
|
|
||||||
const HAS_TY_PROJECTION = 1 << 10;
|
|
||||||
/// Does this have `Inherent`?
|
|
||||||
const HAS_TY_INHERENT = 1 << 11;
|
|
||||||
/// Does this have `Opaque`?
|
|
||||||
const HAS_TY_OPAQUE = 1 << 12;
|
|
||||||
/// Does this have `ConstKind::Unevaluated`?
|
|
||||||
const HAS_CT_PROJECTION = 1 << 13;
|
|
||||||
|
|
||||||
/// Could this type be normalized further?
|
|
||||||
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
|
|
||||||
| TypeFlags::HAS_TY_OPAQUE.bits
|
|
||||||
| TypeFlags::HAS_TY_INHERENT.bits
|
|
||||||
| TypeFlags::HAS_CT_PROJECTION.bits;
|
|
||||||
|
|
||||||
/// Is an error type/const reachable?
|
|
||||||
const HAS_ERROR = 1 << 14;
|
|
||||||
|
|
||||||
/// Does this have any region that "appears free" in the type?
|
|
||||||
/// Basically anything but `ReLateBound` and `ReErased`.
|
|
||||||
const HAS_FREE_REGIONS = 1 << 15;
|
|
||||||
|
|
||||||
/// Does this have any `ReLateBound` regions?
|
|
||||||
const HAS_RE_LATE_BOUND = 1 << 16;
|
|
||||||
/// Does this have any `Bound` types?
|
|
||||||
const HAS_TY_LATE_BOUND = 1 << 17;
|
|
||||||
/// Does this have any `ConstKind::Bound` consts?
|
|
||||||
const HAS_CT_LATE_BOUND = 1 << 18;
|
|
||||||
/// Does this have any bound variables?
|
|
||||||
/// Used to check if a global bound is safe to evaluate.
|
|
||||||
const HAS_LATE_BOUND = TypeFlags::HAS_RE_LATE_BOUND.bits
|
|
||||||
| TypeFlags::HAS_TY_LATE_BOUND.bits
|
|
||||||
| TypeFlags::HAS_CT_LATE_BOUND.bits;
|
|
||||||
|
|
||||||
/// Does this have any `ReErased` regions?
|
|
||||||
const HAS_RE_ERASED = 1 << 19;
|
|
||||||
|
|
||||||
/// Does this value have parameters/placeholders/inference variables which could be
|
|
||||||
/// replaced later, in a way that would change the results of `impl` specialization?
|
|
||||||
const STILL_FURTHER_SPECIALIZABLE = 1 << 20;
|
|
||||||
|
|
||||||
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
|
|
||||||
const HAS_TY_FRESH = 1 << 21;
|
|
||||||
|
|
||||||
/// Does this value have `InferConst::Fresh`?
|
|
||||||
const HAS_CT_FRESH = 1 << 22;
|
|
||||||
|
|
||||||
/// Does this have `Generator` or `GeneratorWitness`?
|
|
||||||
const HAS_TY_GENERATOR = 1 << 23;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
/// A [De Bruijn index][dbi] is a standard means of representing
|
/// A [De Bruijn index][dbi] is a standard means of representing
|
||||||
/// regions (and perhaps later types) in a higher-ranked setting. In
|
/// regions (and perhaps later types) in a higher-ranked setting. In
|
||||||
@ -434,259 +167,6 @@ pub fn debug_bound_var<T: std::fmt::Write>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
|
||||||
pub enum IntTy {
|
|
||||||
Isize,
|
|
||||||
I8,
|
|
||||||
I16,
|
|
||||||
I32,
|
|
||||||
I64,
|
|
||||||
I128,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntTy {
|
|
||||||
pub fn name_str(&self) -> &'static str {
|
|
||||||
match *self {
|
|
||||||
IntTy::Isize => "isize",
|
|
||||||
IntTy::I8 => "i8",
|
|
||||||
IntTy::I16 => "i16",
|
|
||||||
IntTy::I32 => "i32",
|
|
||||||
IntTy::I64 => "i64",
|
|
||||||
IntTy::I128 => "i128",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bit_width(&self) -> Option<u64> {
|
|
||||||
Some(match *self {
|
|
||||||
IntTy::Isize => return None,
|
|
||||||
IntTy::I8 => 8,
|
|
||||||
IntTy::I16 => 16,
|
|
||||||
IntTy::I32 => 32,
|
|
||||||
IntTy::I64 => 64,
|
|
||||||
IntTy::I128 => 128,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn normalize(&self, target_width: u32) -> Self {
|
|
||||||
match self {
|
|
||||||
IntTy::Isize => match target_width {
|
|
||||||
16 => IntTy::I16,
|
|
||||||
32 => IntTy::I32,
|
|
||||||
64 => IntTy::I64,
|
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
|
||||||
_ => *self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_unsigned(self) -> UintTy {
|
|
||||||
match self {
|
|
||||||
IntTy::Isize => UintTy::Usize,
|
|
||||||
IntTy::I8 => UintTy::U8,
|
|
||||||
IntTy::I16 => UintTy::U16,
|
|
||||||
IntTy::I32 => UintTy::U32,
|
|
||||||
IntTy::I64 => UintTy::U64,
|
|
||||||
IntTy::I128 => UintTy::U128,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
|
|
||||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
|
||||||
pub enum UintTy {
|
|
||||||
Usize,
|
|
||||||
U8,
|
|
||||||
U16,
|
|
||||||
U32,
|
|
||||||
U64,
|
|
||||||
U128,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UintTy {
|
|
||||||
pub fn name_str(&self) -> &'static str {
|
|
||||||
match *self {
|
|
||||||
UintTy::Usize => "usize",
|
|
||||||
UintTy::U8 => "u8",
|
|
||||||
UintTy::U16 => "u16",
|
|
||||||
UintTy::U32 => "u32",
|
|
||||||
UintTy::U64 => "u64",
|
|
||||||
UintTy::U128 => "u128",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bit_width(&self) -> Option<u64> {
|
|
||||||
Some(match *self {
|
|
||||||
UintTy::Usize => return None,
|
|
||||||
UintTy::U8 => 8,
|
|
||||||
UintTy::U16 => 16,
|
|
||||||
UintTy::U32 => 32,
|
|
||||||
UintTy::U64 => 64,
|
|
||||||
UintTy::U128 => 128,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn normalize(&self, target_width: u32) -> Self {
|
|
||||||
match self {
|
|
||||||
UintTy::Usize => match target_width {
|
|
||||||
16 => UintTy::U16,
|
|
||||||
32 => UintTy::U32,
|
|
||||||
64 => UintTy::U64,
|
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
|
||||||
_ => *self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_signed(self) -> IntTy {
|
|
||||||
match self {
|
|
||||||
UintTy::Usize => IntTy::Isize,
|
|
||||||
UintTy::U8 => IntTy::I8,
|
|
||||||
UintTy::U16 => IntTy::I16,
|
|
||||||
UintTy::U32 => IntTy::I32,
|
|
||||||
UintTy::U64 => IntTy::I64,
|
|
||||||
UintTy::U128 => IntTy::I128,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
|
||||||
pub enum FloatTy {
|
|
||||||
F32,
|
|
||||||
F64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FloatTy {
|
|
||||||
pub fn name_str(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
FloatTy::F32 => "f32",
|
|
||||||
FloatTy::F64 => "f64",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bit_width(self) -> u64 {
|
|
||||||
match self {
|
|
||||||
FloatTy::F32 => 32,
|
|
||||||
FloatTy::F64 => 64,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum IntVarValue {
|
|
||||||
IntType(IntTy),
|
|
||||||
UintType(UintTy),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub struct FloatVarValue(pub FloatTy);
|
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
|
||||||
/// A **ty**pe **v**ariable **ID**.
|
|
||||||
#[debug_format = "?{}t"]
|
|
||||||
pub struct TyVid {}
|
|
||||||
}
|
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
|
||||||
/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
|
|
||||||
#[debug_format = "?{}i"]
|
|
||||||
pub struct IntVid {}
|
|
||||||
}
|
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
|
||||||
/// A **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
|
|
||||||
#[debug_format = "?{}f"]
|
|
||||||
pub struct FloatVid {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A placeholder for a type that hasn't been inferred yet.
|
|
||||||
///
|
|
||||||
/// E.g., if we have an empty array (`[]`), then we create a fresh
|
|
||||||
/// type variable for the element type since we won't know until it's
|
|
||||||
/// used what the element type is supposed to be.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
|
|
||||||
pub enum InferTy {
|
|
||||||
/// A type variable.
|
|
||||||
TyVar(TyVid),
|
|
||||||
/// An integral type variable (`{integer}`).
|
|
||||||
///
|
|
||||||
/// These are created when the compiler sees an integer literal like
|
|
||||||
/// `1` that could be several different types (`u8`, `i32`, `u32`, etc.).
|
|
||||||
/// We don't know until it's used what type it's supposed to be, so
|
|
||||||
/// we create a fresh type variable.
|
|
||||||
IntVar(IntVid),
|
|
||||||
/// A floating-point type variable (`{float}`).
|
|
||||||
///
|
|
||||||
/// These are created when the compiler sees an float literal like
|
|
||||||
/// `1.0` that could be either an `f32` or an `f64`.
|
|
||||||
/// We don't know until it's used what type it's supposed to be, so
|
|
||||||
/// we create a fresh type variable.
|
|
||||||
FloatVar(FloatVid),
|
|
||||||
|
|
||||||
/// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
|
|
||||||
/// for an unbound type variable. This is convenient for caching etc. See
|
|
||||||
/// `rustc_infer::infer::freshen` for more details.
|
|
||||||
///
|
|
||||||
/// Compare with [`TyVar`][Self::TyVar].
|
|
||||||
FreshTy(u32),
|
|
||||||
/// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar].
|
|
||||||
FreshIntTy(u32),
|
|
||||||
/// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar].
|
|
||||||
FreshFloatTy(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Raw `TyVid` are used as the unification key for `sub_relations`;
|
|
||||||
/// they carry no values.
|
|
||||||
impl UnifyKey for TyVid {
|
|
||||||
type Value = ();
|
|
||||||
#[inline]
|
|
||||||
fn index(&self) -> u32 {
|
|
||||||
self.as_u32()
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_index(i: u32) -> TyVid {
|
|
||||||
TyVid::from_u32(i)
|
|
||||||
}
|
|
||||||
fn tag() -> &'static str {
|
|
||||||
"TyVid"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EqUnifyValue for IntVarValue {}
|
|
||||||
|
|
||||||
impl UnifyKey for IntVid {
|
|
||||||
type Value = Option<IntVarValue>;
|
|
||||||
#[inline] // make this function eligible for inlining - it is quite hot.
|
|
||||||
fn index(&self) -> u32 {
|
|
||||||
self.as_u32()
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_index(i: u32) -> IntVid {
|
|
||||||
IntVid::from_u32(i)
|
|
||||||
}
|
|
||||||
fn tag() -> &'static str {
|
|
||||||
"IntVid"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EqUnifyValue for FloatVarValue {}
|
|
||||||
|
|
||||||
impl UnifyKey for FloatVid {
|
|
||||||
type Value = Option<FloatVarValue>;
|
|
||||||
#[inline]
|
|
||||||
fn index(&self) -> u32 {
|
|
||||||
self.as_u32()
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_index(i: u32) -> FloatVid {
|
|
||||||
FloatVid::from_u32(i)
|
|
||||||
}
|
|
||||||
fn tag() -> &'static str {
|
|
||||||
"FloatVid"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Decodable, Encodable, Hash, HashStable_Generic)]
|
#[derive(Copy, Clone, PartialEq, Eq, Decodable, Encodable, Hash, HashStable_Generic)]
|
||||||
#[rustc_pass_by_value]
|
#[rustc_pass_by_value]
|
||||||
pub enum Variance {
|
pub enum Variance {
|
||||||
@ -756,34 +236,6 @@ impl Variance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CTX> HashStable<CTX> for InferTy {
|
|
||||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
|
||||||
use InferTy::*;
|
|
||||||
discriminant(self).hash_stable(ctx, hasher);
|
|
||||||
match self {
|
|
||||||
TyVar(_) | IntVar(_) | FloatVar(_) => {
|
|
||||||
panic!("type variables should not be hashed: {self:?}")
|
|
||||||
}
|
|
||||||
FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for IntVarValue {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
IntVarValue::IntType(ref v) => v.fmt(f),
|
|
||||||
IntVarValue::UintType(ref v) => v.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for FloatVarValue {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Variance {
|
impl fmt::Debug for Variance {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.write_str(match *self {
|
f.write_str(match *self {
|
||||||
@ -795,20 +247,6 @@ impl fmt::Debug for Variance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for InferTy {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
use InferTy::*;
|
|
||||||
match *self {
|
|
||||||
TyVar(_) => write!(f, "_"),
|
|
||||||
IntVar(_) => write!(f, "{}", "{integer}"),
|
|
||||||
FloatVar(_) => write!(f, "{}", "{float}"),
|
|
||||||
FreshTy(v) => write!(f, "FreshTy({v})"),
|
|
||||||
FreshIntTy(v) => write!(f, "FreshIntTy({v})"),
|
|
||||||
FreshFloatTy(v) => write!(f, "FreshFloatTy({v})"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
/// "Universes" are used during type- and trait-checking in the
|
/// "Universes" are used during type- and trait-checking in the
|
||||||
/// presence of `for<..>` binders to control what sets of names are
|
/// presence of `for<..>` binders to control what sets of names are
|
||||||
|
@ -33,3 +33,20 @@ macro_rules! TrivialTypeTraversalImpls {
|
|||||||
)+
|
)+
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Atomic structs
|
||||||
|
//
|
||||||
|
// For things that don't carry any arena-allocated data (and are
|
||||||
|
// copy...), just add them to this list.
|
||||||
|
|
||||||
|
TrivialTypeTraversalImpls! {
|
||||||
|
(),
|
||||||
|
bool,
|
||||||
|
usize,
|
||||||
|
u16,
|
||||||
|
u32,
|
||||||
|
u64,
|
||||||
|
String,
|
||||||
|
crate::DebruijnIndex,
|
||||||
|
}
|
||||||
|
412
compiler/rustc_type_ir/src/region_kind.rs
Normal file
412
compiler/rustc_type_ir/src/region_kind.rs
Normal file
@ -0,0 +1,412 @@
|
|||||||
|
use rustc_data_structures::stable_hasher::HashStable;
|
||||||
|
use rustc_serialize::{Decodable, Decoder, Encodable};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt;
|
||||||
|
use std::hash;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx,
|
||||||
|
TyDecoder, TyEncoder,
|
||||||
|
};
|
||||||
|
|
||||||
|
use self::RegionKind::*;
|
||||||
|
|
||||||
|
/// Representation of regions. Note that the NLL checker uses a distinct
|
||||||
|
/// representation of regions. For this reason, it internally replaces all the
|
||||||
|
/// regions with inference variables -- the index of the variable is then used
|
||||||
|
/// to index into internal NLL data structures. See `rustc_const_eval::borrow_check`
|
||||||
|
/// module for more information.
|
||||||
|
///
|
||||||
|
/// Note: operations are on the wrapper `Region` type, which is interned,
|
||||||
|
/// rather than this type.
|
||||||
|
///
|
||||||
|
/// ## The Region lattice within a given function
|
||||||
|
///
|
||||||
|
/// In general, the region lattice looks like
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// static ----------+-----...------+ (greatest)
|
||||||
|
/// | | |
|
||||||
|
/// early-bound and | |
|
||||||
|
/// free regions | |
|
||||||
|
/// | | |
|
||||||
|
/// | | |
|
||||||
|
/// empty(root) placeholder(U1) |
|
||||||
|
/// | / |
|
||||||
|
/// | / placeholder(Un)
|
||||||
|
/// empty(U1) -- /
|
||||||
|
/// | /
|
||||||
|
/// ... /
|
||||||
|
/// | /
|
||||||
|
/// empty(Un) -------- (smallest)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Early-bound/free regions are the named lifetimes in scope from the
|
||||||
|
/// function declaration. They have relationships to one another
|
||||||
|
/// determined based on the declared relationships from the
|
||||||
|
/// function.
|
||||||
|
///
|
||||||
|
/// Note that inference variables and bound regions are not included
|
||||||
|
/// in this diagram. In the case of inference variables, they should
|
||||||
|
/// be inferred to some other region from the diagram. In the case of
|
||||||
|
/// bound regions, they are excluded because they don't make sense to
|
||||||
|
/// include -- the diagram indicates the relationship between free
|
||||||
|
/// regions.
|
||||||
|
///
|
||||||
|
/// ## Inference variables
|
||||||
|
///
|
||||||
|
/// During region inference, we sometimes create inference variables,
|
||||||
|
/// represented as `ReVar`. These will be inferred by the code in
|
||||||
|
/// `infer::lexical_region_resolve` to some free region from the
|
||||||
|
/// lattice above (the minimal region that meets the
|
||||||
|
/// constraints).
|
||||||
|
///
|
||||||
|
/// During NLL checking, where regions are defined differently, we
|
||||||
|
/// also use `ReVar` -- in that case, the index is used to index into
|
||||||
|
/// the NLL region checker's data structures. The variable may in fact
|
||||||
|
/// represent either a free region or an inference variable, in that
|
||||||
|
/// case.
|
||||||
|
///
|
||||||
|
/// ## Bound Regions
|
||||||
|
///
|
||||||
|
/// These are regions that are stored behind a binder and must be substituted
|
||||||
|
/// with some concrete region before being used. There are two kind of
|
||||||
|
/// bound regions: early-bound, which are bound in an item's `Generics`,
|
||||||
|
/// and are substituted by an `GenericArgs`, and late-bound, which are part of
|
||||||
|
/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by
|
||||||
|
/// the likes of `liberate_late_bound_regions`. The distinction exists
|
||||||
|
/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
|
||||||
|
///
|
||||||
|
/// Unlike `Param`s, bound regions are not supposed to exist "in the wild"
|
||||||
|
/// outside their binder, e.g., in types passed to type inference, and
|
||||||
|
/// should first be substituted (by placeholder regions, free regions,
|
||||||
|
/// or region variables).
|
||||||
|
///
|
||||||
|
/// ## Placeholder and Free Regions
|
||||||
|
///
|
||||||
|
/// One often wants to work with bound regions without knowing their precise
|
||||||
|
/// identity. For example, when checking a function, the lifetime of a borrow
|
||||||
|
/// can end up being assigned to some region parameter. In these cases,
|
||||||
|
/// it must be ensured that bounds on the region can't be accidentally
|
||||||
|
/// assumed without being checked.
|
||||||
|
///
|
||||||
|
/// To do this, we replace the bound regions with placeholder markers,
|
||||||
|
/// which don't satisfy any relation not explicitly provided.
|
||||||
|
///
|
||||||
|
/// There are two kinds of placeholder regions in rustc: `ReFree` and
|
||||||
|
/// `RePlaceholder`. When checking an item's body, `ReFree` is supposed
|
||||||
|
/// to be used. These also support explicit bounds: both the internally-stored
|
||||||
|
/// *scope*, which the region is assumed to outlive, as well as other
|
||||||
|
/// relations stored in the `FreeRegionMap`. Note that these relations
|
||||||
|
/// aren't checked when you `make_subregion` (or `eq_types`), only by
|
||||||
|
/// `resolve_regions_and_report_errors`.
|
||||||
|
///
|
||||||
|
/// When working with higher-ranked types, some region relations aren't
|
||||||
|
/// yet known, so you can't just call `resolve_regions_and_report_errors`.
|
||||||
|
/// `RePlaceholder` is designed for this purpose. In these contexts,
|
||||||
|
/// there's also the risk that some inference variable laying around will
|
||||||
|
/// get unified with your placeholder region: if you want to check whether
|
||||||
|
/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
|
||||||
|
/// with a placeholder region `'%a`, the variable `'_` would just be
|
||||||
|
/// instantiated to the placeholder region `'%a`, which is wrong because
|
||||||
|
/// the inference variable is supposed to satisfy the relation
|
||||||
|
/// *for every value of the placeholder region*. To ensure that doesn't
|
||||||
|
/// happen, you can use `leak_check`. This is more clearly explained
|
||||||
|
/// by the [rustc dev guide].
|
||||||
|
///
|
||||||
|
/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
|
||||||
|
/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
|
||||||
|
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
|
||||||
|
pub enum RegionKind<I: Interner> {
|
||||||
|
/// Region bound in a type or fn declaration which will be
|
||||||
|
/// substituted 'early' -- that is, at the same time when type
|
||||||
|
/// parameters are substituted.
|
||||||
|
ReEarlyBound(I::EarlyBoundRegion),
|
||||||
|
|
||||||
|
/// Region bound in a function scope, which will be substituted when the
|
||||||
|
/// function is called.
|
||||||
|
ReLateBound(DebruijnIndex, I::BoundRegion),
|
||||||
|
|
||||||
|
/// When checking a function body, the types of all arguments and so forth
|
||||||
|
/// that refer to bound region parameters are modified to refer to free
|
||||||
|
/// region parameters.
|
||||||
|
ReFree(I::FreeRegion),
|
||||||
|
|
||||||
|
/// Static data that has an "infinite" lifetime. Top in the region lattice.
|
||||||
|
ReStatic,
|
||||||
|
|
||||||
|
/// A region variable. Should not exist outside of type inference.
|
||||||
|
ReVar(I::InferRegion),
|
||||||
|
|
||||||
|
/// A placeholder region -- basically, the higher-ranked version of `ReFree`.
|
||||||
|
/// Should not exist outside of type inference.
|
||||||
|
RePlaceholder(I::PlaceholderRegion),
|
||||||
|
|
||||||
|
/// Erased region, used by trait selection, in MIR and during codegen.
|
||||||
|
ReErased,
|
||||||
|
|
||||||
|
/// A region that resulted from some other error. Used exclusively for diagnostics.
|
||||||
|
ReError(I::ErrorGuaranteed),
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is manually implemented for `RegionKind` because `std::mem::discriminant`
|
||||||
|
// returns an opaque value that is `PartialEq` but not `PartialOrd`
|
||||||
|
#[inline]
|
||||||
|
const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize {
|
||||||
|
match value {
|
||||||
|
ReEarlyBound(_) => 0,
|
||||||
|
ReLateBound(_, _) => 1,
|
||||||
|
ReFree(_) => 2,
|
||||||
|
ReStatic => 3,
|
||||||
|
ReVar(_) => 4,
|
||||||
|
RePlaceholder(_) => 5,
|
||||||
|
ReErased => 6,
|
||||||
|
ReError(_) => 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is manually implemented because a derive would require `I: Copy`
|
||||||
|
impl<I: Interner> Copy for RegionKind<I>
|
||||||
|
where
|
||||||
|
I::EarlyBoundRegion: Copy,
|
||||||
|
I::BoundRegion: Copy,
|
||||||
|
I::FreeRegion: Copy,
|
||||||
|
I::InferRegion: Copy,
|
||||||
|
I::PlaceholderRegion: Copy,
|
||||||
|
I::ErrorGuaranteed: Copy,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is manually implemented because a derive would require `I: Clone`
|
||||||
|
impl<I: Interner> Clone for RegionKind<I> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
ReEarlyBound(r) => ReEarlyBound(r.clone()),
|
||||||
|
ReLateBound(d, r) => ReLateBound(*d, r.clone()),
|
||||||
|
ReFree(r) => ReFree(r.clone()),
|
||||||
|
ReStatic => ReStatic,
|
||||||
|
ReVar(r) => ReVar(r.clone()),
|
||||||
|
RePlaceholder(r) => RePlaceholder(r.clone()),
|
||||||
|
ReErased => ReErased,
|
||||||
|
ReError(r) => ReError(r.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is manually implemented because a derive would require `I: PartialEq`
|
||||||
|
impl<I: Interner> PartialEq for RegionKind<I> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &RegionKind<I>) -> bool {
|
||||||
|
regionkind_discriminant(self) == regionkind_discriminant(other)
|
||||||
|
&& match (self, other) {
|
||||||
|
(ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r == b_r,
|
||||||
|
(ReLateBound(a_d, a_r), ReLateBound(b_d, b_r)) => a_d == b_d && a_r == b_r,
|
||||||
|
(ReFree(a_r), ReFree(b_r)) => a_r == b_r,
|
||||||
|
(ReStatic, ReStatic) => true,
|
||||||
|
(ReVar(a_r), ReVar(b_r)) => a_r == b_r,
|
||||||
|
(RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r,
|
||||||
|
(ReErased, ReErased) => true,
|
||||||
|
(ReError(_), ReError(_)) => true,
|
||||||
|
_ => {
|
||||||
|
debug_assert!(
|
||||||
|
false,
|
||||||
|
"This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
|
||||||
|
);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is manually implemented because a derive would require `I: Eq`
|
||||||
|
impl<I: Interner> Eq for RegionKind<I> {}
|
||||||
|
|
||||||
|
// This is manually implemented because a derive would require `I: PartialOrd`
|
||||||
|
impl<I: Interner> PartialOrd for RegionKind<I> {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, other: &RegionKind<I>) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is manually implemented because a derive would require `I: Ord`
|
||||||
|
impl<I: Interner> Ord for RegionKind<I> {
|
||||||
|
#[inline]
|
||||||
|
fn cmp(&self, other: &RegionKind<I>) -> Ordering {
|
||||||
|
regionkind_discriminant(self).cmp(®ionkind_discriminant(other)).then_with(|| {
|
||||||
|
match (self, other) {
|
||||||
|
(ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r.cmp(b_r),
|
||||||
|
(ReLateBound(a_d, a_r), ReLateBound(b_d, b_r)) => {
|
||||||
|
a_d.cmp(b_d).then_with(|| a_r.cmp(b_r))
|
||||||
|
}
|
||||||
|
(ReFree(a_r), ReFree(b_r)) => a_r.cmp(b_r),
|
||||||
|
(ReStatic, ReStatic) => Ordering::Equal,
|
||||||
|
(ReVar(a_r), ReVar(b_r)) => a_r.cmp(b_r),
|
||||||
|
(RePlaceholder(a_r), RePlaceholder(b_r)) => a_r.cmp(b_r),
|
||||||
|
(ReErased, ReErased) => Ordering::Equal,
|
||||||
|
_ => {
|
||||||
|
debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}");
|
||||||
|
Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is manually implemented because a derive would require `I: Hash`
|
||||||
|
impl<I: Interner> hash::Hash for RegionKind<I> {
|
||||||
|
fn hash<H: hash::Hasher>(&self, state: &mut H) -> () {
|
||||||
|
regionkind_discriminant(self).hash(state);
|
||||||
|
match self {
|
||||||
|
ReEarlyBound(r) => r.hash(state),
|
||||||
|
ReLateBound(d, r) => {
|
||||||
|
d.hash(state);
|
||||||
|
r.hash(state)
|
||||||
|
}
|
||||||
|
ReFree(r) => r.hash(state),
|
||||||
|
ReStatic => (),
|
||||||
|
ReVar(r) => r.hash(state),
|
||||||
|
RePlaceholder(r) => r.hash(state),
|
||||||
|
ReErased => (),
|
||||||
|
ReError(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
match this.data {
|
||||||
|
ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"),
|
||||||
|
|
||||||
|
ReLateBound(binder_id, bound_region) => {
|
||||||
|
write!(f, "ReLateBound({binder_id:?}, {bound_region:?})")
|
||||||
|
}
|
||||||
|
|
||||||
|
ReFree(fr) => write!(f, "{fr:?}"),
|
||||||
|
|
||||||
|
ReStatic => f.write_str("ReStatic"),
|
||||||
|
|
||||||
|
ReVar(vid) => write!(f, "{:?}", &this.wrap(vid)),
|
||||||
|
|
||||||
|
RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"),
|
||||||
|
|
||||||
|
ReErased => f.write_str("ReErased"),
|
||||||
|
|
||||||
|
ReError(_) => f.write_str("ReError"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<I: Interner> fmt::Debug for RegionKind<I> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is manually implemented because a derive would require `I: Encodable`
|
||||||
|
impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I>
|
||||||
|
where
|
||||||
|
I::EarlyBoundRegion: Encodable<E>,
|
||||||
|
I::BoundRegion: Encodable<E>,
|
||||||
|
I::FreeRegion: Encodable<E>,
|
||||||
|
I::InferRegion: Encodable<E>,
|
||||||
|
I::PlaceholderRegion: Encodable<E>,
|
||||||
|
{
|
||||||
|
fn encode(&self, e: &mut E) {
|
||||||
|
let disc = regionkind_discriminant(self);
|
||||||
|
match self {
|
||||||
|
ReEarlyBound(a) => e.emit_enum_variant(disc, |e| {
|
||||||
|
a.encode(e);
|
||||||
|
}),
|
||||||
|
ReLateBound(a, b) => e.emit_enum_variant(disc, |e| {
|
||||||
|
a.encode(e);
|
||||||
|
b.encode(e);
|
||||||
|
}),
|
||||||
|
ReFree(a) => e.emit_enum_variant(disc, |e| {
|
||||||
|
a.encode(e);
|
||||||
|
}),
|
||||||
|
ReStatic => e.emit_enum_variant(disc, |_| {}),
|
||||||
|
ReVar(a) => e.emit_enum_variant(disc, |e| {
|
||||||
|
a.encode(e);
|
||||||
|
}),
|
||||||
|
RePlaceholder(a) => e.emit_enum_variant(disc, |e| {
|
||||||
|
a.encode(e);
|
||||||
|
}),
|
||||||
|
ReErased => e.emit_enum_variant(disc, |_| {}),
|
||||||
|
ReError(_) => e.emit_enum_variant(disc, |_| {}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is manually implemented because a derive would require `I: Decodable`
|
||||||
|
impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for RegionKind<I>
|
||||||
|
where
|
||||||
|
I::EarlyBoundRegion: Decodable<D>,
|
||||||
|
I::BoundRegion: Decodable<D>,
|
||||||
|
I::FreeRegion: Decodable<D>,
|
||||||
|
I::InferRegion: Decodable<D>,
|
||||||
|
I::PlaceholderRegion: Decodable<D>,
|
||||||
|
I::ErrorGuaranteed: Decodable<D>,
|
||||||
|
{
|
||||||
|
fn decode(d: &mut D) -> Self {
|
||||||
|
match Decoder::read_usize(d) {
|
||||||
|
0 => ReEarlyBound(Decodable::decode(d)),
|
||||||
|
1 => ReLateBound(Decodable::decode(d), Decodable::decode(d)),
|
||||||
|
2 => ReFree(Decodable::decode(d)),
|
||||||
|
3 => ReStatic,
|
||||||
|
4 => ReVar(Decodable::decode(d)),
|
||||||
|
5 => RePlaceholder(Decodable::decode(d)),
|
||||||
|
6 => ReErased,
|
||||||
|
7 => ReError(Decodable::decode(d)),
|
||||||
|
_ => panic!(
|
||||||
|
"{}",
|
||||||
|
format!(
|
||||||
|
"invalid enum variant tag while decoding `{}`, expected 0..{}",
|
||||||
|
"RegionKind", 8,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not a derived impl because a derive would require `I: HashStable`
|
||||||
|
impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for RegionKind<I>
|
||||||
|
where
|
||||||
|
I::EarlyBoundRegion: HashStable<CTX>,
|
||||||
|
I::BoundRegion: HashStable<CTX>,
|
||||||
|
I::FreeRegion: HashStable<CTX>,
|
||||||
|
I::InferRegion: HashStable<CTX>,
|
||||||
|
I::PlaceholderRegion: HashStable<CTX>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn hash_stable(
|
||||||
|
&self,
|
||||||
|
hcx: &mut CTX,
|
||||||
|
hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
|
||||||
|
) {
|
||||||
|
std::mem::discriminant(self).hash_stable(hcx, hasher);
|
||||||
|
match self {
|
||||||
|
ReErased | ReStatic | ReError(_) => {
|
||||||
|
// No variant fields to hash for these ...
|
||||||
|
}
|
||||||
|
ReLateBound(d, r) => {
|
||||||
|
d.hash_stable(hcx, hasher);
|
||||||
|
r.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
ReEarlyBound(r) => {
|
||||||
|
r.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
ReFree(r) => {
|
||||||
|
r.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
RePlaceholder(r) => {
|
||||||
|
r.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
ReVar(_) => {
|
||||||
|
panic!("region variables should not be hashed: {self:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,390 +0,0 @@
|
|||||||
//! This module contains implementations of the `TypeFoldable` and `TypeVisitable`
|
|
||||||
//! traits for various types in the Rust compiler. Most are written by hand, though
|
|
||||||
//! we've recently added some macros and proc-macros to help with the tedium.
|
|
||||||
|
|
||||||
use crate::fold::{FallibleTypeFolder, TypeFoldable};
|
|
||||||
use crate::visit::{TypeVisitable, TypeVisitor};
|
|
||||||
use crate::{ConstKind, FloatTy, InferTy, IntTy, Interner, UintTy, UniverseIndex};
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
|
||||||
use rustc_index::{Idx, IndexVec};
|
|
||||||
|
|
||||||
use core::fmt;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::mem;
|
|
||||||
use std::ops::ControlFlow;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Atomic structs
|
|
||||||
//
|
|
||||||
// For things that don't carry any arena-allocated data (and are
|
|
||||||
// copy...), just add them to this list.
|
|
||||||
|
|
||||||
TrivialTypeTraversalImpls! {
|
|
||||||
(),
|
|
||||||
bool,
|
|
||||||
usize,
|
|
||||||
u16,
|
|
||||||
u32,
|
|
||||||
u64,
|
|
||||||
String,
|
|
||||||
crate::DebruijnIndex,
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Traversal implementations.
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeFoldable<I>, U: TypeFoldable<I>> TypeFoldable<I> for (T, U) {
|
|
||||||
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
|
|
||||||
Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeVisitable<I>, U: TypeVisitable<I>> TypeVisitable<I> for (T, U) {
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
self.0.visit_with(visitor)?;
|
|
||||||
self.1.visit_with(visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, A: TypeFoldable<I>, B: TypeFoldable<I>, C: TypeFoldable<I>> TypeFoldable<I>
|
|
||||||
for (A, B, C)
|
|
||||||
{
|
|
||||||
fn try_fold_with<F: FallibleTypeFolder<I>>(
|
|
||||||
self,
|
|
||||||
folder: &mut F,
|
|
||||||
) -> Result<(A, B, C), F::Error> {
|
|
||||||
Ok((
|
|
||||||
self.0.try_fold_with(folder)?,
|
|
||||||
self.1.try_fold_with(folder)?,
|
|
||||||
self.2.try_fold_with(folder)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, A: TypeVisitable<I>, B: TypeVisitable<I>, C: TypeVisitable<I>> TypeVisitable<I>
|
|
||||||
for (A, B, C)
|
|
||||||
{
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
self.0.visit_with(visitor)?;
|
|
||||||
self.1.visit_with(visitor)?;
|
|
||||||
self.2.visit_with(visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Option<T> {
|
|
||||||
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
|
||||||
Ok(match self {
|
|
||||||
Some(v) => Some(v.try_fold_with(folder)?),
|
|
||||||
None => None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Option<T> {
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
match self {
|
|
||||||
Some(v) => v.visit_with(visitor),
|
|
||||||
None => ControlFlow::Continue(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>> TypeFoldable<I> for Result<T, E> {
|
|
||||||
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
|
||||||
Ok(match self {
|
|
||||||
Ok(v) => Ok(v.try_fold_with(folder)?),
|
|
||||||
Err(e) => Err(e.try_fold_with(folder)?),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for Result<T, E> {
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
match self {
|
|
||||||
Ok(v) => v.visit_with(visitor),
|
|
||||||
Err(e) => e.visit_with(visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Lrc<T> {
|
|
||||||
fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
|
|
||||||
// We merely want to replace the contained `T`, if at all possible,
|
|
||||||
// so that we don't needlessly allocate a new `Lrc` or indeed clone
|
|
||||||
// the contained type.
|
|
||||||
unsafe {
|
|
||||||
// First step is to ensure that we have a unique reference to
|
|
||||||
// the contained type, which `Lrc::make_mut` will accomplish (by
|
|
||||||
// allocating a new `Lrc` and cloning the `T` only if required).
|
|
||||||
// This is done *before* casting to `Lrc<ManuallyDrop<T>>` so that
|
|
||||||
// panicking during `make_mut` does not leak the `T`.
|
|
||||||
Lrc::make_mut(&mut self);
|
|
||||||
|
|
||||||
// Casting to `Lrc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
|
|
||||||
// is `repr(transparent)`.
|
|
||||||
let ptr = Lrc::into_raw(self).cast::<mem::ManuallyDrop<T>>();
|
|
||||||
let mut unique = Lrc::from_raw(ptr);
|
|
||||||
|
|
||||||
// Call to `Lrc::make_mut` above guarantees that `unique` is the
|
|
||||||
// sole reference to the contained value, so we can avoid doing
|
|
||||||
// a checked `get_mut` here.
|
|
||||||
let slot = Lrc::get_mut_unchecked(&mut unique);
|
|
||||||
|
|
||||||
// Semantically move the contained type out from `unique`, fold
|
|
||||||
// it, then move the folded value back into `unique`. Should
|
|
||||||
// folding fail, `ManuallyDrop` ensures that the "moved-out"
|
|
||||||
// value is not re-dropped.
|
|
||||||
let owned = mem::ManuallyDrop::take(slot);
|
|
||||||
let folded = owned.try_fold_with(folder)?;
|
|
||||||
*slot = mem::ManuallyDrop::new(folded);
|
|
||||||
|
|
||||||
// Cast back to `Lrc<T>`.
|
|
||||||
Ok(Lrc::from_raw(Lrc::into_raw(unique).cast()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Lrc<T> {
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
(**self).visit_with(visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<T> {
|
|
||||||
fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
|
|
||||||
*self = (*self).try_fold_with(folder)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<T> {
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
(**self).visit_with(visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> {
|
|
||||||
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
|
||||||
self.into_iter().map(|t| t.try_fold_with(folder)).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Vec<T> {
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
self.iter().try_for_each(|t| t.visit_with(visitor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general
|
|
||||||
// case, because we can't return a new slice. But note that there are a couple
|
|
||||||
// of trivial impls of `TypeFoldable` for specific slice types elsewhere.
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] {
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
self.iter().try_for_each(|t| t.visit_with(visitor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
self.iter().try_for_each(|t| t.visit_with(visitor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, T> {
|
|
||||||
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
|
||||||
self.raw.try_fold_with(folder).map(IndexVec::from_raw)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix, T> {
|
|
||||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
|
||||||
self.iter().try_for_each(|t| t.visit_with(visitor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////
|
|
||||||
// Debug impls
|
|
||||||
|
|
||||||
pub trait InferCtxtLike<I: Interner> {
|
|
||||||
fn universe_of_ty(&self, ty: I::InferTy) -> Option<UniverseIndex>;
|
|
||||||
fn universe_of_lt(&self, lt: I::InferRegion) -> Option<UniverseIndex>;
|
|
||||||
fn universe_of_ct(&self, ct: I::InferConst) -> Option<UniverseIndex>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> InferCtxtLike<I> for core::convert::Infallible {
|
|
||||||
fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> {
|
|
||||||
match *self {}
|
|
||||||
}
|
|
||||||
fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> {
|
|
||||||
match *self {}
|
|
||||||
}
|
|
||||||
fn universe_of_lt(&self, _lt: <I as Interner>::InferRegion) -> Option<UniverseIndex> {
|
|
||||||
match *self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait DebugWithInfcx<I: Interner>: fmt::Debug {
|
|
||||||
fn fmt<InfCtx: InferCtxtLike<I>>(
|
|
||||||
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
) -> fmt::Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
|
|
||||||
fn fmt<InfCtx: InferCtxtLike<I>>(
|
|
||||||
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
<T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
|
|
||||||
fn fmt<InfCtx: InferCtxtLike<I>>(
|
|
||||||
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
match f.alternate() {
|
|
||||||
true => {
|
|
||||||
write!(f, "[\n")?;
|
|
||||||
for element in this.data.iter() {
|
|
||||||
write!(f, "{:?},\n", &this.wrap(element))?;
|
|
||||||
}
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
false => {
|
|
||||||
write!(f, "[")?;
|
|
||||||
if this.data.len() > 0 {
|
|
||||||
for element in &this.data[..(this.data.len() - 1)] {
|
|
||||||
write!(f, "{:?}, ", &this.wrap(element))?;
|
|
||||||
}
|
|
||||||
if let Some(element) = this.data.last() {
|
|
||||||
write!(f, "{:?}", &this.wrap(element))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OptWithInfcx<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> {
|
|
||||||
pub data: T,
|
|
||||||
pub infcx: Option<&'a InfCtx>,
|
|
||||||
_interner: PhantomData<I>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Copy> Copy for OptWithInfcx<'_, I, InfCtx, T> {}
|
|
||||||
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Clone> Clone for OptWithInfcx<'_, I, InfCtx, T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self { data: self.data.clone(), infcx: self.infcx, _interner: self._interner }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I: Interner, T> OptWithInfcx<'a, I, core::convert::Infallible, T> {
|
|
||||||
pub fn new_no_ctx(data: T) -> Self {
|
|
||||||
Self { data, infcx: None, _interner: PhantomData }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> OptWithInfcx<'a, I, InfCtx, T> {
|
|
||||||
pub fn new(data: T, infcx: &'a InfCtx) -> Self {
|
|
||||||
Self { data, infcx: Some(infcx), _interner: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wrap<U>(self, u: U) -> OptWithInfcx<'a, I, InfCtx, U> {
|
|
||||||
OptWithInfcx { data: u, infcx: self.infcx, _interner: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptWithInfcx<'a, I, InfCtx, U> {
|
|
||||||
OptWithInfcx { data: f(self.data), infcx: self.infcx, _interner: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ref(&self) -> OptWithInfcx<'a, I, InfCtx, &T> {
|
|
||||||
OptWithInfcx { data: &self.data, infcx: self.infcx, _interner: PhantomData }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: DebugWithInfcx<I>> fmt::Debug
|
|
||||||
for OptWithInfcx<'_, I, InfCtx, T>
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
DebugWithInfcx::fmt(self.as_ref(), f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for IntTy {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.name_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for UintTy {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.name_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for FloatTy {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.name_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for InferTy {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
use InferTy::*;
|
|
||||||
match *self {
|
|
||||||
TyVar(ref v) => v.fmt(f),
|
|
||||||
IntVar(ref v) => v.fmt(f),
|
|
||||||
FloatVar(ref v) => v.fmt(f),
|
|
||||||
FreshTy(v) => write!(f, "FreshTy({v:?})"),
|
|
||||||
FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"),
|
|
||||||
FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy {
|
|
||||||
fn fmt<InfCtx: InferCtxtLike<I>>(
|
|
||||||
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
use InferTy::*;
|
|
||||||
match this.infcx.and_then(|infcx| infcx.universe_of_ty(*this.data)) {
|
|
||||||
None => write!(f, "{:?}", this.data),
|
|
||||||
Some(universe) => match *this.data {
|
|
||||||
TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()),
|
|
||||||
IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> fmt::Debug for ConstKind<I> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
OptWithInfcx::new_no_ctx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
|
|
||||||
fn fmt<InfCtx: InferCtxtLike<I>>(
|
|
||||||
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
|
||||||
) -> core::fmt::Result {
|
|
||||||
use ConstKind::*;
|
|
||||||
|
|
||||||
match this.data {
|
|
||||||
Param(param) => write!(f, "{param:?}"),
|
|
||||||
Infer(var) => write!(f, "{:?}", &this.wrap(var)),
|
|
||||||
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()),
|
|
||||||
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
|
||||||
Unevaluated(uv) => {
|
|
||||||
write!(f, "{:?}", &this.wrap(uv))
|
|
||||||
}
|
|
||||||
Value(valtree) => write!(f, "{valtree:?}"),
|
|
||||||
Error(_) => write!(f, "{{const error}}"),
|
|
||||||
Expr(expr) => write!(f, "{:?}", &this.wrap(expr)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +1,8 @@
|
|||||||
use std::{
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
cmp::Ordering,
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
hash::{Hash, Hasher},
|
use std::cmp::Ordering;
|
||||||
ops::Deref,
|
use std::hash::{Hash, Hasher};
|
||||||
};
|
use std::ops::Deref;
|
||||||
|
|
||||||
use rustc_data_structures::{
|
|
||||||
fingerprint::Fingerprint,
|
|
||||||
stable_hasher::{HashStable, StableHasher},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{DebruijnIndex, TypeFlags};
|
use crate::{DebruijnIndex, TypeFlags};
|
||||||
|
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
#![allow(rustc::usage_of_ty_tykind)]
|
#![allow(rustc::usage_of_ty_tykind)]
|
||||||
|
|
||||||
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
|
use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
|
||||||
|
use rustc_serialize::{Decodable, Decoder, Encodable};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::mem::discriminant;
|
||||||
use std::{fmt, hash};
|
use std::{fmt, hash};
|
||||||
|
|
||||||
use crate::FloatTy;
|
|
||||||
use crate::HashStableContext;
|
use crate::HashStableContext;
|
||||||
use crate::IntTy;
|
|
||||||
use crate::Interner;
|
use crate::Interner;
|
||||||
use crate::TyDecoder;
|
use crate::TyDecoder;
|
||||||
use crate::TyEncoder;
|
use crate::TyEncoder;
|
||||||
use crate::UintTy;
|
|
||||||
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
||||||
|
|
||||||
use self::RegionKind::*;
|
|
||||||
use self::TyKind::*;
|
use self::TyKind::*;
|
||||||
|
|
||||||
use rustc_data_structures::stable_hasher::HashStable;
|
|
||||||
use rustc_serialize::{Decodable, Decoder, Encodable};
|
|
||||||
|
|
||||||
/// The movability of a generator / closure literal:
|
/// The movability of a generator / closure literal:
|
||||||
/// whether a generator contains self-references, causing it to be `!Unpin`.
|
/// whether a generator contains self-references, causing it to be `!Unpin`.
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug, Copy)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug, Copy)]
|
||||||
@ -914,620 +911,347 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a constant in Rust.
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
// #[derive(derive_more::From)]
|
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||||
pub enum ConstKind<I: Interner> {
|
pub enum IntTy {
|
||||||
/// A const generic parameter.
|
Isize,
|
||||||
Param(I::ParamConst),
|
I8,
|
||||||
|
I16,
|
||||||
/// Infer the value of the const.
|
I32,
|
||||||
Infer(I::InferConst),
|
I64,
|
||||||
|
I128,
|
||||||
/// Bound const variable, used only when preparing a trait query.
|
|
||||||
Bound(DebruijnIndex, I::BoundConst),
|
|
||||||
|
|
||||||
/// A placeholder const - universally quantified higher-ranked const.
|
|
||||||
Placeholder(I::PlaceholderConst),
|
|
||||||
|
|
||||||
/// An unnormalized const item such as an anon const or assoc const or free const item.
|
|
||||||
/// Right now anything other than anon consts does not actually work properly but this
|
|
||||||
/// should
|
|
||||||
Unevaluated(I::AliasConst),
|
|
||||||
|
|
||||||
/// Used to hold computed value.
|
|
||||||
Value(I::ValueConst),
|
|
||||||
|
|
||||||
/// A placeholder for a const which could not be computed; this is
|
|
||||||
/// propagated to avoid useless error messages.
|
|
||||||
Error(I::ErrorGuaranteed),
|
|
||||||
|
|
||||||
/// Unevaluated non-const-item, used by `feature(generic_const_exprs)` to represent
|
|
||||||
/// const arguments such as `N + 1` or `foo(N)`
|
|
||||||
Expr(I::ExprConst),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn const_kind_discriminant<I: Interner>(value: &ConstKind<I>) -> usize {
|
impl IntTy {
|
||||||
match value {
|
pub fn name_str(&self) -> &'static str {
|
||||||
ConstKind::Param(_) => 0,
|
match *self {
|
||||||
ConstKind::Infer(_) => 1,
|
IntTy::Isize => "isize",
|
||||||
ConstKind::Bound(_, _) => 2,
|
IntTy::I8 => "i8",
|
||||||
ConstKind::Placeholder(_) => 3,
|
IntTy::I16 => "i16",
|
||||||
ConstKind::Unevaluated(_) => 4,
|
IntTy::I32 => "i32",
|
||||||
ConstKind::Value(_) => 5,
|
IntTy::I64 => "i64",
|
||||||
ConstKind::Error(_) => 6,
|
IntTy::I128 => "i128",
|
||||||
ConstKind::Expr(_) => 7,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> hash::Hash for ConstKind<I> {
|
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
|
||||||
const_kind_discriminant(self).hash(state);
|
|
||||||
match self {
|
|
||||||
ConstKind::Param(p) => p.hash(state),
|
|
||||||
ConstKind::Infer(i) => i.hash(state),
|
|
||||||
ConstKind::Bound(d, b) => {
|
|
||||||
d.hash(state);
|
|
||||||
b.hash(state);
|
|
||||||
}
|
|
||||||
ConstKind::Placeholder(p) => p.hash(state),
|
|
||||||
ConstKind::Unevaluated(u) => u.hash(state),
|
|
||||||
ConstKind::Value(v) => v.hash(state),
|
|
||||||
ConstKind::Error(e) => e.hash(state),
|
|
||||||
ConstKind::Expr(e) => e.hash(state),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ConstKind<I>
|
pub fn bit_width(&self) -> Option<u64> {
|
||||||
where
|
Some(match *self {
|
||||||
I::ParamConst: HashStable<CTX>,
|
IntTy::Isize => return None,
|
||||||
I::InferConst: HashStable<CTX>,
|
IntTy::I8 => 8,
|
||||||
I::BoundConst: HashStable<CTX>,
|
IntTy::I16 => 16,
|
||||||
I::PlaceholderConst: HashStable<CTX>,
|
IntTy::I32 => 32,
|
||||||
I::AliasConst: HashStable<CTX>,
|
IntTy::I64 => 64,
|
||||||
I::ValueConst: HashStable<CTX>,
|
IntTy::I128 => 128,
|
||||||
I::ErrorGuaranteed: HashStable<CTX>,
|
|
||||||
I::ExprConst: HashStable<CTX>,
|
|
||||||
{
|
|
||||||
fn hash_stable(
|
|
||||||
&self,
|
|
||||||
hcx: &mut CTX,
|
|
||||||
hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
|
|
||||||
) {
|
|
||||||
const_kind_discriminant(self).hash_stable(hcx, hasher);
|
|
||||||
match self {
|
|
||||||
ConstKind::Param(p) => p.hash_stable(hcx, hasher),
|
|
||||||
ConstKind::Infer(i) => i.hash_stable(hcx, hasher),
|
|
||||||
ConstKind::Bound(d, b) => {
|
|
||||||
d.hash_stable(hcx, hasher);
|
|
||||||
b.hash_stable(hcx, hasher);
|
|
||||||
}
|
|
||||||
ConstKind::Placeholder(p) => p.hash_stable(hcx, hasher),
|
|
||||||
ConstKind::Unevaluated(u) => u.hash_stable(hcx, hasher),
|
|
||||||
ConstKind::Value(v) => v.hash_stable(hcx, hasher),
|
|
||||||
ConstKind::Error(e) => e.hash_stable(hcx, hasher),
|
|
||||||
ConstKind::Expr(e) => e.hash_stable(hcx, hasher),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for ConstKind<I>
|
|
||||||
where
|
|
||||||
I::ParamConst: Decodable<D>,
|
|
||||||
I::InferConst: Decodable<D>,
|
|
||||||
I::BoundConst: Decodable<D>,
|
|
||||||
I::PlaceholderConst: Decodable<D>,
|
|
||||||
I::AliasConst: Decodable<D>,
|
|
||||||
I::ValueConst: Decodable<D>,
|
|
||||||
I::ErrorGuaranteed: Decodable<D>,
|
|
||||||
I::ExprConst: Decodable<D>,
|
|
||||||
{
|
|
||||||
fn decode(d: &mut D) -> Self {
|
|
||||||
match Decoder::read_usize(d) {
|
|
||||||
0 => ConstKind::Param(Decodable::decode(d)),
|
|
||||||
1 => ConstKind::Infer(Decodable::decode(d)),
|
|
||||||
2 => ConstKind::Bound(Decodable::decode(d), Decodable::decode(d)),
|
|
||||||
3 => ConstKind::Placeholder(Decodable::decode(d)),
|
|
||||||
4 => ConstKind::Unevaluated(Decodable::decode(d)),
|
|
||||||
5 => ConstKind::Value(Decodable::decode(d)),
|
|
||||||
6 => ConstKind::Error(Decodable::decode(d)),
|
|
||||||
7 => ConstKind::Expr(Decodable::decode(d)),
|
|
||||||
_ => panic!(
|
|
||||||
"{}",
|
|
||||||
format!(
|
|
||||||
"invalid enum variant tag while decoding `{}`, expected 0..{}",
|
|
||||||
"ConstKind", 8,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for ConstKind<I>
|
|
||||||
where
|
|
||||||
I::ParamConst: Encodable<E>,
|
|
||||||
I::InferConst: Encodable<E>,
|
|
||||||
I::BoundConst: Encodable<E>,
|
|
||||||
I::PlaceholderConst: Encodable<E>,
|
|
||||||
I::AliasConst: Encodable<E>,
|
|
||||||
I::ValueConst: Encodable<E>,
|
|
||||||
I::ErrorGuaranteed: Encodable<E>,
|
|
||||||
I::ExprConst: Encodable<E>,
|
|
||||||
{
|
|
||||||
fn encode(&self, e: &mut E) {
|
|
||||||
let disc = const_kind_discriminant(self);
|
|
||||||
match self {
|
|
||||||
ConstKind::Param(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
|
|
||||||
ConstKind::Infer(i) => e.emit_enum_variant(disc, |e| i.encode(e)),
|
|
||||||
ConstKind::Bound(d, b) => e.emit_enum_variant(disc, |e| {
|
|
||||||
d.encode(e);
|
|
||||||
b.encode(e);
|
|
||||||
}),
|
|
||||||
ConstKind::Placeholder(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
|
|
||||||
ConstKind::Unevaluated(u) => e.emit_enum_variant(disc, |e| u.encode(e)),
|
|
||||||
ConstKind::Value(v) => e.emit_enum_variant(disc, |e| v.encode(e)),
|
|
||||||
ConstKind::Error(er) => e.emit_enum_variant(disc, |e| er.encode(e)),
|
|
||||||
ConstKind::Expr(ex) => e.emit_enum_variant(disc, |e| ex.encode(e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> PartialOrd for ConstKind<I> {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> Ord for ConstKind<I> {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
const_kind_discriminant(self)
|
|
||||||
.cmp(&const_kind_discriminant(other))
|
|
||||||
.then_with(|| match (self, other) {
|
|
||||||
(ConstKind::Param(p1), ConstKind::Param(p2)) => p1.cmp(p2),
|
|
||||||
(ConstKind::Infer(i1), ConstKind::Infer(i2)) => i1.cmp(i2),
|
|
||||||
(ConstKind::Bound(d1, b1), ConstKind::Bound(d2, b2)) => d1.cmp(d2).then_with(|| b1.cmp(b2)),
|
|
||||||
(ConstKind::Placeholder(p1), ConstKind::Placeholder(p2)) => p1.cmp(p2),
|
|
||||||
(ConstKind::Unevaluated(u1), ConstKind::Unevaluated(u2)) => u1.cmp(u2),
|
|
||||||
(ConstKind::Value(v1), ConstKind::Value(v2)) => v1.cmp(v2),
|
|
||||||
(ConstKind::Error(e1), ConstKind::Error(e2)) => e1.cmp(e2),
|
|
||||||
(ConstKind::Expr(e1), ConstKind::Expr(e2)) => e1.cmp(e2),
|
|
||||||
_ => {
|
|
||||||
debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}");
|
|
||||||
Ordering::Equal
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> PartialEq for ConstKind<I> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
match (self, other) {
|
|
||||||
(Self::Param(l0), Self::Param(r0)) => l0 == r0,
|
|
||||||
(Self::Infer(l0), Self::Infer(r0)) => l0 == r0,
|
|
||||||
(Self::Bound(l0, l1), Self::Bound(r0, r1)) => l0 == r0 && l1 == r1,
|
|
||||||
(Self::Placeholder(l0), Self::Placeholder(r0)) => l0 == r0,
|
|
||||||
(Self::Unevaluated(l0), Self::Unevaluated(r0)) => l0 == r0,
|
|
||||||
(Self::Value(l0), Self::Value(r0)) => l0 == r0,
|
|
||||||
(Self::Error(l0), Self::Error(r0)) => l0 == r0,
|
|
||||||
(Self::Expr(l0), Self::Expr(r0)) => l0 == r0,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Interner> Eq for ConstKind<I> {}
|
|
||||||
|
|
||||||
impl<I: Interner> Clone for ConstKind<I> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Param(arg0) => Self::Param(arg0.clone()),
|
|
||||||
Self::Infer(arg0) => Self::Infer(arg0.clone()),
|
|
||||||
Self::Bound(arg0, arg1) => Self::Bound(arg0.clone(), arg1.clone()),
|
|
||||||
Self::Placeholder(arg0) => Self::Placeholder(arg0.clone()),
|
|
||||||
Self::Unevaluated(arg0) => Self::Unevaluated(arg0.clone()),
|
|
||||||
Self::Value(arg0) => Self::Value(arg0.clone()),
|
|
||||||
Self::Error(arg0) => Self::Error(arg0.clone()),
|
|
||||||
Self::Expr(arg0) => Self::Expr(arg0.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Representation of regions. Note that the NLL checker uses a distinct
|
|
||||||
/// representation of regions. For this reason, it internally replaces all the
|
|
||||||
/// regions with inference variables -- the index of the variable is then used
|
|
||||||
/// to index into internal NLL data structures. See `rustc_const_eval::borrow_check`
|
|
||||||
/// module for more information.
|
|
||||||
///
|
|
||||||
/// Note: operations are on the wrapper `Region` type, which is interned,
|
|
||||||
/// rather than this type.
|
|
||||||
///
|
|
||||||
/// ## The Region lattice within a given function
|
|
||||||
///
|
|
||||||
/// In general, the region lattice looks like
|
|
||||||
///
|
|
||||||
/// ```text
|
|
||||||
/// static ----------+-----...------+ (greatest)
|
|
||||||
/// | | |
|
|
||||||
/// early-bound and | |
|
|
||||||
/// free regions | |
|
|
||||||
/// | | |
|
|
||||||
/// | | |
|
|
||||||
/// empty(root) placeholder(U1) |
|
|
||||||
/// | / |
|
|
||||||
/// | / placeholder(Un)
|
|
||||||
/// empty(U1) -- /
|
|
||||||
/// | /
|
|
||||||
/// ... /
|
|
||||||
/// | /
|
|
||||||
/// empty(Un) -------- (smallest)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Early-bound/free regions are the named lifetimes in scope from the
|
|
||||||
/// function declaration. They have relationships to one another
|
|
||||||
/// determined based on the declared relationships from the
|
|
||||||
/// function.
|
|
||||||
///
|
|
||||||
/// Note that inference variables and bound regions are not included
|
|
||||||
/// in this diagram. In the case of inference variables, they should
|
|
||||||
/// be inferred to some other region from the diagram. In the case of
|
|
||||||
/// bound regions, they are excluded because they don't make sense to
|
|
||||||
/// include -- the diagram indicates the relationship between free
|
|
||||||
/// regions.
|
|
||||||
///
|
|
||||||
/// ## Inference variables
|
|
||||||
///
|
|
||||||
/// During region inference, we sometimes create inference variables,
|
|
||||||
/// represented as `ReVar`. These will be inferred by the code in
|
|
||||||
/// `infer::lexical_region_resolve` to some free region from the
|
|
||||||
/// lattice above (the minimal region that meets the
|
|
||||||
/// constraints).
|
|
||||||
///
|
|
||||||
/// During NLL checking, where regions are defined differently, we
|
|
||||||
/// also use `ReVar` -- in that case, the index is used to index into
|
|
||||||
/// the NLL region checker's data structures. The variable may in fact
|
|
||||||
/// represent either a free region or an inference variable, in that
|
|
||||||
/// case.
|
|
||||||
///
|
|
||||||
/// ## Bound Regions
|
|
||||||
///
|
|
||||||
/// These are regions that are stored behind a binder and must be substituted
|
|
||||||
/// with some concrete region before being used. There are two kind of
|
|
||||||
/// bound regions: early-bound, which are bound in an item's `Generics`,
|
|
||||||
/// and are substituted by an `GenericArgs`, and late-bound, which are part of
|
|
||||||
/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by
|
|
||||||
/// the likes of `liberate_late_bound_regions`. The distinction exists
|
|
||||||
/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
|
|
||||||
///
|
|
||||||
/// Unlike `Param`s, bound regions are not supposed to exist "in the wild"
|
|
||||||
/// outside their binder, e.g., in types passed to type inference, and
|
|
||||||
/// should first be substituted (by placeholder regions, free regions,
|
|
||||||
/// or region variables).
|
|
||||||
///
|
|
||||||
/// ## Placeholder and Free Regions
|
|
||||||
///
|
|
||||||
/// One often wants to work with bound regions without knowing their precise
|
|
||||||
/// identity. For example, when checking a function, the lifetime of a borrow
|
|
||||||
/// can end up being assigned to some region parameter. In these cases,
|
|
||||||
/// it must be ensured that bounds on the region can't be accidentally
|
|
||||||
/// assumed without being checked.
|
|
||||||
///
|
|
||||||
/// To do this, we replace the bound regions with placeholder markers,
|
|
||||||
/// which don't satisfy any relation not explicitly provided.
|
|
||||||
///
|
|
||||||
/// There are two kinds of placeholder regions in rustc: `ReFree` and
|
|
||||||
/// `RePlaceholder`. When checking an item's body, `ReFree` is supposed
|
|
||||||
/// to be used. These also support explicit bounds: both the internally-stored
|
|
||||||
/// *scope*, which the region is assumed to outlive, as well as other
|
|
||||||
/// relations stored in the `FreeRegionMap`. Note that these relations
|
|
||||||
/// aren't checked when you `make_subregion` (or `eq_types`), only by
|
|
||||||
/// `resolve_regions_and_report_errors`.
|
|
||||||
///
|
|
||||||
/// When working with higher-ranked types, some region relations aren't
|
|
||||||
/// yet known, so you can't just call `resolve_regions_and_report_errors`.
|
|
||||||
/// `RePlaceholder` is designed for this purpose. In these contexts,
|
|
||||||
/// there's also the risk that some inference variable laying around will
|
|
||||||
/// get unified with your placeholder region: if you want to check whether
|
|
||||||
/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
|
|
||||||
/// with a placeholder region `'%a`, the variable `'_` would just be
|
|
||||||
/// instantiated to the placeholder region `'%a`, which is wrong because
|
|
||||||
/// the inference variable is supposed to satisfy the relation
|
|
||||||
/// *for every value of the placeholder region*. To ensure that doesn't
|
|
||||||
/// happen, you can use `leak_check`. This is more clearly explained
|
|
||||||
/// by the [rustc dev guide].
|
|
||||||
///
|
|
||||||
/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
|
|
||||||
/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
|
|
||||||
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
|
|
||||||
pub enum RegionKind<I: Interner> {
|
|
||||||
/// Region bound in a type or fn declaration which will be
|
|
||||||
/// substituted 'early' -- that is, at the same time when type
|
|
||||||
/// parameters are substituted.
|
|
||||||
ReEarlyBound(I::EarlyBoundRegion),
|
|
||||||
|
|
||||||
/// Region bound in a function scope, which will be substituted when the
|
|
||||||
/// function is called.
|
|
||||||
ReLateBound(DebruijnIndex, I::BoundRegion),
|
|
||||||
|
|
||||||
/// When checking a function body, the types of all arguments and so forth
|
|
||||||
/// that refer to bound region parameters are modified to refer to free
|
|
||||||
/// region parameters.
|
|
||||||
ReFree(I::FreeRegion),
|
|
||||||
|
|
||||||
/// Static data that has an "infinite" lifetime. Top in the region lattice.
|
|
||||||
ReStatic,
|
|
||||||
|
|
||||||
/// A region variable. Should not exist outside of type inference.
|
|
||||||
ReVar(I::InferRegion),
|
|
||||||
|
|
||||||
/// A placeholder region -- basically, the higher-ranked version of `ReFree`.
|
|
||||||
/// Should not exist outside of type inference.
|
|
||||||
RePlaceholder(I::PlaceholderRegion),
|
|
||||||
|
|
||||||
/// Erased region, used by trait selection, in MIR and during codegen.
|
|
||||||
ReErased,
|
|
||||||
|
|
||||||
/// A region that resulted from some other error. Used exclusively for diagnostics.
|
|
||||||
ReError(I::ErrorGuaranteed),
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is manually implemented for `RegionKind` because `std::mem::discriminant`
|
|
||||||
// returns an opaque value that is `PartialEq` but not `PartialOrd`
|
|
||||||
#[inline]
|
|
||||||
const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize {
|
|
||||||
match value {
|
|
||||||
ReEarlyBound(_) => 0,
|
|
||||||
ReLateBound(_, _) => 1,
|
|
||||||
ReFree(_) => 2,
|
|
||||||
ReStatic => 3,
|
|
||||||
ReVar(_) => 4,
|
|
||||||
RePlaceholder(_) => 5,
|
|
||||||
ReErased => 6,
|
|
||||||
ReError(_) => 7,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Copy`
|
|
||||||
impl<I: Interner> Copy for RegionKind<I>
|
|
||||||
where
|
|
||||||
I::EarlyBoundRegion: Copy,
|
|
||||||
I::BoundRegion: Copy,
|
|
||||||
I::FreeRegion: Copy,
|
|
||||||
I::InferRegion: Copy,
|
|
||||||
I::PlaceholderRegion: Copy,
|
|
||||||
I::ErrorGuaranteed: Copy,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Clone`
|
|
||||||
impl<I: Interner> Clone for RegionKind<I> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
match self {
|
|
||||||
ReEarlyBound(r) => ReEarlyBound(r.clone()),
|
|
||||||
ReLateBound(d, r) => ReLateBound(*d, r.clone()),
|
|
||||||
ReFree(r) => ReFree(r.clone()),
|
|
||||||
ReStatic => ReStatic,
|
|
||||||
ReVar(r) => ReVar(r.clone()),
|
|
||||||
RePlaceholder(r) => RePlaceholder(r.clone()),
|
|
||||||
ReErased => ReErased,
|
|
||||||
ReError(r) => ReError(r.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: PartialEq`
|
|
||||||
impl<I: Interner> PartialEq for RegionKind<I> {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &RegionKind<I>) -> bool {
|
|
||||||
regionkind_discriminant(self) == regionkind_discriminant(other)
|
|
||||||
&& match (self, other) {
|
|
||||||
(ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r == b_r,
|
|
||||||
(ReLateBound(a_d, a_r), ReLateBound(b_d, b_r)) => a_d == b_d && a_r == b_r,
|
|
||||||
(ReFree(a_r), ReFree(b_r)) => a_r == b_r,
|
|
||||||
(ReStatic, ReStatic) => true,
|
|
||||||
(ReVar(a_r), ReVar(b_r)) => a_r == b_r,
|
|
||||||
(RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r,
|
|
||||||
(ReErased, ReErased) => true,
|
|
||||||
(ReError(_), ReError(_)) => true,
|
|
||||||
_ => {
|
|
||||||
debug_assert!(
|
|
||||||
false,
|
|
||||||
"This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
|
|
||||||
);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Eq`
|
|
||||||
impl<I: Interner> Eq for RegionKind<I> {}
|
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: PartialOrd`
|
|
||||||
impl<I: Interner> PartialOrd for RegionKind<I> {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &RegionKind<I>) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Ord`
|
|
||||||
impl<I: Interner> Ord for RegionKind<I> {
|
|
||||||
#[inline]
|
|
||||||
fn cmp(&self, other: &RegionKind<I>) -> Ordering {
|
|
||||||
regionkind_discriminant(self).cmp(®ionkind_discriminant(other)).then_with(|| {
|
|
||||||
match (self, other) {
|
|
||||||
(ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r.cmp(b_r),
|
|
||||||
(ReLateBound(a_d, a_r), ReLateBound(b_d, b_r)) => {
|
|
||||||
a_d.cmp(b_d).then_with(|| a_r.cmp(b_r))
|
|
||||||
}
|
|
||||||
(ReFree(a_r), ReFree(b_r)) => a_r.cmp(b_r),
|
|
||||||
(ReStatic, ReStatic) => Ordering::Equal,
|
|
||||||
(ReVar(a_r), ReVar(b_r)) => a_r.cmp(b_r),
|
|
||||||
(RePlaceholder(a_r), RePlaceholder(b_r)) => a_r.cmp(b_r),
|
|
||||||
(ReErased, ReErased) => Ordering::Equal,
|
|
||||||
_ => {
|
|
||||||
debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}");
|
|
||||||
Ordering::Equal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Hash`
|
pub fn normalize(&self, target_width: u32) -> Self {
|
||||||
impl<I: Interner> hash::Hash for RegionKind<I> {
|
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) -> () {
|
|
||||||
regionkind_discriminant(self).hash(state);
|
|
||||||
match self {
|
match self {
|
||||||
ReEarlyBound(r) => r.hash(state),
|
IntTy::Isize => match target_width {
|
||||||
ReLateBound(d, r) => {
|
16 => IntTy::I16,
|
||||||
d.hash(state);
|
32 => IntTy::I32,
|
||||||
r.hash(state)
|
64 => IntTy::I64,
|
||||||
}
|
_ => unreachable!(),
|
||||||
ReFree(r) => r.hash(state),
|
},
|
||||||
ReStatic => (),
|
_ => *self,
|
||||||
ReVar(r) => r.hash(state),
|
}
|
||||||
RePlaceholder(r) => r.hash(state),
|
}
|
||||||
ReErased => (),
|
|
||||||
ReError(_) => (),
|
pub fn to_unsigned(self) -> UintTy {
|
||||||
|
match self {
|
||||||
|
IntTy::Isize => UintTy::Usize,
|
||||||
|
IntTy::I8 => UintTy::U8,
|
||||||
|
IntTy::I16 => UintTy::U16,
|
||||||
|
IntTy::I32 => UintTy::U32,
|
||||||
|
IntTy::I64 => UintTy::U64,
|
||||||
|
IntTy::I128 => UintTy::U128,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
|
||||||
|
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||||
|
pub enum UintTy {
|
||||||
|
Usize,
|
||||||
|
U8,
|
||||||
|
U16,
|
||||||
|
U32,
|
||||||
|
U64,
|
||||||
|
U128,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UintTy {
|
||||||
|
pub fn name_str(&self) -> &'static str {
|
||||||
|
match *self {
|
||||||
|
UintTy::Usize => "usize",
|
||||||
|
UintTy::U8 => "u8",
|
||||||
|
UintTy::U16 => "u16",
|
||||||
|
UintTy::U32 => "u32",
|
||||||
|
UintTy::U64 => "u64",
|
||||||
|
UintTy::U128 => "u128",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bit_width(&self) -> Option<u64> {
|
||||||
|
Some(match *self {
|
||||||
|
UintTy::Usize => return None,
|
||||||
|
UintTy::U8 => 8,
|
||||||
|
UintTy::U16 => 16,
|
||||||
|
UintTy::U32 => 32,
|
||||||
|
UintTy::U64 => 64,
|
||||||
|
UintTy::U128 => 128,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalize(&self, target_width: u32) -> Self {
|
||||||
|
match self {
|
||||||
|
UintTy::Usize => match target_width {
|
||||||
|
16 => UintTy::U16,
|
||||||
|
32 => UintTy::U32,
|
||||||
|
64 => UintTy::U64,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
_ => *self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_signed(self) -> IntTy {
|
||||||
|
match self {
|
||||||
|
UintTy::Usize => IntTy::Isize,
|
||||||
|
UintTy::U8 => IntTy::I8,
|
||||||
|
UintTy::U16 => IntTy::I16,
|
||||||
|
UintTy::U32 => IntTy::I32,
|
||||||
|
UintTy::U64 => IntTy::I64,
|
||||||
|
UintTy::U128 => IntTy::I128,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||||
|
pub enum FloatTy {
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatTy {
|
||||||
|
pub fn name_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
FloatTy::F32 => "f32",
|
||||||
|
FloatTy::F64 => "f64",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bit_width(self) -> u64 {
|
||||||
|
match self {
|
||||||
|
FloatTy::F32 => 32,
|
||||||
|
FloatTy::F64 => 64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum IntVarValue {
|
||||||
|
IntType(IntTy),
|
||||||
|
UintType(UintTy),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct FloatVarValue(pub FloatTy);
|
||||||
|
|
||||||
|
rustc_index::newtype_index! {
|
||||||
|
/// A **ty**pe **v**ariable **ID**.
|
||||||
|
#[debug_format = "?{}t"]
|
||||||
|
pub struct TyVid {}
|
||||||
|
}
|
||||||
|
|
||||||
|
rustc_index::newtype_index! {
|
||||||
|
/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
|
||||||
|
#[debug_format = "?{}i"]
|
||||||
|
pub struct IntVid {}
|
||||||
|
}
|
||||||
|
|
||||||
|
rustc_index::newtype_index! {
|
||||||
|
/// A **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
|
||||||
|
#[debug_format = "?{}f"]
|
||||||
|
pub struct FloatVid {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A placeholder for a type that hasn't been inferred yet.
|
||||||
|
///
|
||||||
|
/// E.g., if we have an empty array (`[]`), then we create a fresh
|
||||||
|
/// type variable for the element type since we won't know until it's
|
||||||
|
/// used what the element type is supposed to be.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
|
||||||
|
pub enum InferTy {
|
||||||
|
/// A type variable.
|
||||||
|
TyVar(TyVid),
|
||||||
|
/// An integral type variable (`{integer}`).
|
||||||
|
///
|
||||||
|
/// These are created when the compiler sees an integer literal like
|
||||||
|
/// `1` that could be several different types (`u8`, `i32`, `u32`, etc.).
|
||||||
|
/// We don't know until it's used what type it's supposed to be, so
|
||||||
|
/// we create a fresh type variable.
|
||||||
|
IntVar(IntVid),
|
||||||
|
/// A floating-point type variable (`{float}`).
|
||||||
|
///
|
||||||
|
/// These are created when the compiler sees an float literal like
|
||||||
|
/// `1.0` that could be either an `f32` or an `f64`.
|
||||||
|
/// We don't know until it's used what type it's supposed to be, so
|
||||||
|
/// we create a fresh type variable.
|
||||||
|
FloatVar(FloatVid),
|
||||||
|
|
||||||
|
/// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
|
||||||
|
/// for an unbound type variable. This is convenient for caching etc. See
|
||||||
|
/// `rustc_infer::infer::freshen` for more details.
|
||||||
|
///
|
||||||
|
/// Compare with [`TyVar`][Self::TyVar].
|
||||||
|
FreshTy(u32),
|
||||||
|
/// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar].
|
||||||
|
FreshIntTy(u32),
|
||||||
|
/// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar].
|
||||||
|
FreshFloatTy(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raw `TyVid` are used as the unification key for `sub_relations`;
|
||||||
|
/// they carry no values.
|
||||||
|
impl UnifyKey for TyVid {
|
||||||
|
type Value = ();
|
||||||
|
#[inline]
|
||||||
|
fn index(&self) -> u32 {
|
||||||
|
self.as_u32()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn from_index(i: u32) -> TyVid {
|
||||||
|
TyVid::from_u32(i)
|
||||||
|
}
|
||||||
|
fn tag() -> &'static str {
|
||||||
|
"TyVid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EqUnifyValue for IntVarValue {}
|
||||||
|
|
||||||
|
impl UnifyKey for IntVid {
|
||||||
|
type Value = Option<IntVarValue>;
|
||||||
|
#[inline] // make this function eligible for inlining - it is quite hot.
|
||||||
|
fn index(&self) -> u32 {
|
||||||
|
self.as_u32()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn from_index(i: u32) -> IntVid {
|
||||||
|
IntVid::from_u32(i)
|
||||||
|
}
|
||||||
|
fn tag() -> &'static str {
|
||||||
|
"IntVid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EqUnifyValue for FloatVarValue {}
|
||||||
|
|
||||||
|
impl UnifyKey for FloatVid {
|
||||||
|
type Value = Option<FloatVarValue>;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self) -> u32 {
|
||||||
|
self.as_u32()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn from_index(i: u32) -> FloatVid {
|
||||||
|
FloatVid::from_u32(i)
|
||||||
|
}
|
||||||
|
fn tag() -> &'static str {
|
||||||
|
"FloatVid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<CTX> HashStable<CTX> for InferTy {
|
||||||
|
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||||
|
use InferTy::*;
|
||||||
|
discriminant(self).hash_stable(ctx, hasher);
|
||||||
|
match self {
|
||||||
|
TyVar(_) | IntVar(_) | FloatVar(_) => {
|
||||||
|
panic!("type variables should not be hashed: {self:?}")
|
||||||
|
}
|
||||||
|
FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for IntVarValue {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
IntVarValue::IntType(ref v) => v.fmt(f),
|
||||||
|
IntVarValue::UintType(ref v) => v.fmt(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for FloatVarValue {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InferTy {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
use InferTy::*;
|
||||||
|
match *self {
|
||||||
|
TyVar(_) => write!(f, "_"),
|
||||||
|
IntVar(_) => write!(f, "{}", "{integer}"),
|
||||||
|
FloatVar(_) => write!(f, "{}", "{float}"),
|
||||||
|
FreshTy(v) => write!(f, "FreshTy({v})"),
|
||||||
|
FreshIntTy(v) => write!(f, "FreshIntTy({v})"),
|
||||||
|
FreshFloatTy(v) => write!(f, "FreshFloatTy({v})"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for IntTy {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.name_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for UintTy {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.name_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for FloatTy {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.name_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for InferTy {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
use InferTy::*;
|
||||||
|
match *self {
|
||||||
|
TyVar(ref v) => v.fmt(f),
|
||||||
|
IntVar(ref v) => v.fmt(f),
|
||||||
|
FloatVar(ref v) => v.fmt(f),
|
||||||
|
FreshTy(v) => write!(f, "FreshTy({v:?})"),
|
||||||
|
FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"),
|
||||||
|
FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy {
|
||||||
fn fmt<InfCtx: InferCtxtLike<I>>(
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
f: &mut fmt::Formatter<'_>,
|
||||||
) -> core::fmt::Result {
|
) -> fmt::Result {
|
||||||
match this.data {
|
use InferTy::*;
|
||||||
ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"),
|
match this.infcx.and_then(|infcx| infcx.universe_of_ty(*this.data)) {
|
||||||
|
None => write!(f, "{:?}", this.data),
|
||||||
ReLateBound(binder_id, bound_region) => {
|
Some(universe) => match *this.data {
|
||||||
write!(f, "ReLateBound({binder_id:?}, {bound_region:?})")
|
TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()),
|
||||||
}
|
IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => {
|
||||||
|
unreachable!()
|
||||||
ReFree(fr) => write!(f, "{fr:?}"),
|
}
|
||||||
|
},
|
||||||
ReStatic => f.write_str("ReStatic"),
|
|
||||||
|
|
||||||
ReVar(vid) => write!(f, "{:?}", &this.wrap(vid)),
|
|
||||||
|
|
||||||
RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"),
|
|
||||||
|
|
||||||
ReErased => f.write_str("ReErased"),
|
|
||||||
|
|
||||||
ReError(_) => f.write_str("ReError"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I: Interner> fmt::Debug for RegionKind<I> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
OptWithInfcx::new_no_ctx(self).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Encodable`
|
|
||||||
impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I>
|
|
||||||
where
|
|
||||||
I::EarlyBoundRegion: Encodable<E>,
|
|
||||||
I::BoundRegion: Encodable<E>,
|
|
||||||
I::FreeRegion: Encodable<E>,
|
|
||||||
I::InferRegion: Encodable<E>,
|
|
||||||
I::PlaceholderRegion: Encodable<E>,
|
|
||||||
{
|
|
||||||
fn encode(&self, e: &mut E) {
|
|
||||||
let disc = regionkind_discriminant(self);
|
|
||||||
match self {
|
|
||||||
ReEarlyBound(a) => e.emit_enum_variant(disc, |e| {
|
|
||||||
a.encode(e);
|
|
||||||
}),
|
|
||||||
ReLateBound(a, b) => e.emit_enum_variant(disc, |e| {
|
|
||||||
a.encode(e);
|
|
||||||
b.encode(e);
|
|
||||||
}),
|
|
||||||
ReFree(a) => e.emit_enum_variant(disc, |e| {
|
|
||||||
a.encode(e);
|
|
||||||
}),
|
|
||||||
ReStatic => e.emit_enum_variant(disc, |_| {}),
|
|
||||||
ReVar(a) => e.emit_enum_variant(disc, |e| {
|
|
||||||
a.encode(e);
|
|
||||||
}),
|
|
||||||
RePlaceholder(a) => e.emit_enum_variant(disc, |e| {
|
|
||||||
a.encode(e);
|
|
||||||
}),
|
|
||||||
ReErased => e.emit_enum_variant(disc, |_| {}),
|
|
||||||
ReError(_) => e.emit_enum_variant(disc, |_| {}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Decodable`
|
|
||||||
impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for RegionKind<I>
|
|
||||||
where
|
|
||||||
I::EarlyBoundRegion: Decodable<D>,
|
|
||||||
I::BoundRegion: Decodable<D>,
|
|
||||||
I::FreeRegion: Decodable<D>,
|
|
||||||
I::InferRegion: Decodable<D>,
|
|
||||||
I::PlaceholderRegion: Decodable<D>,
|
|
||||||
I::ErrorGuaranteed: Decodable<D>,
|
|
||||||
{
|
|
||||||
fn decode(d: &mut D) -> Self {
|
|
||||||
match Decoder::read_usize(d) {
|
|
||||||
0 => ReEarlyBound(Decodable::decode(d)),
|
|
||||||
1 => ReLateBound(Decodable::decode(d), Decodable::decode(d)),
|
|
||||||
2 => ReFree(Decodable::decode(d)),
|
|
||||||
3 => ReStatic,
|
|
||||||
4 => ReVar(Decodable::decode(d)),
|
|
||||||
5 => RePlaceholder(Decodable::decode(d)),
|
|
||||||
6 => ReErased,
|
|
||||||
7 => ReError(Decodable::decode(d)),
|
|
||||||
_ => panic!(
|
|
||||||
"{}",
|
|
||||||
format!(
|
|
||||||
"invalid enum variant tag while decoding `{}`, expected 0..{}",
|
|
||||||
"RegionKind", 8,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is not a derived impl because a derive would require `I: HashStable`
|
|
||||||
impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for RegionKind<I>
|
|
||||||
where
|
|
||||||
I::EarlyBoundRegion: HashStable<CTX>,
|
|
||||||
I::BoundRegion: HashStable<CTX>,
|
|
||||||
I::FreeRegion: HashStable<CTX>,
|
|
||||||
I::InferRegion: HashStable<CTX>,
|
|
||||||
I::PlaceholderRegion: HashStable<CTX>,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn hash_stable(
|
|
||||||
&self,
|
|
||||||
hcx: &mut CTX,
|
|
||||||
hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
|
|
||||||
) {
|
|
||||||
std::mem::discriminant(self).hash_stable(hcx, hasher);
|
|
||||||
match self {
|
|
||||||
ReErased | ReStatic | ReError(_) => {
|
|
||||||
// No variant fields to hash for these ...
|
|
||||||
}
|
|
||||||
ReLateBound(d, r) => {
|
|
||||||
d.hash_stable(hcx, hasher);
|
|
||||||
r.hash_stable(hcx, hasher);
|
|
||||||
}
|
|
||||||
ReEarlyBound(r) => {
|
|
||||||
r.hash_stable(hcx, hasher);
|
|
||||||
}
|
|
||||||
ReFree(r) => {
|
|
||||||
r.hash_stable(hcx, hasher);
|
|
||||||
}
|
|
||||||
RePlaceholder(r) => {
|
|
||||||
r.hash_stable(hcx, hasher);
|
|
||||||
}
|
|
||||||
ReVar(_) => {
|
|
||||||
panic!("region variables should not be hashed: {self:?}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -40,11 +40,14 @@
|
|||||||
//! - ty.super_visit_with(visitor)
|
//! - ty.super_visit_with(visitor)
|
||||||
//! - u.visit_with(visitor)
|
//! - u.visit_with(visitor)
|
||||||
//! ```
|
//! ```
|
||||||
use crate::Interner;
|
|
||||||
|
|
||||||
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
use rustc_index::{Idx, IndexVec};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::Interner;
|
||||||
|
|
||||||
/// This trait is implemented for every type that can be visited,
|
/// This trait is implemented for every type that can be visited,
|
||||||
/// providing the skeleton of the traversal.
|
/// providing the skeleton of the traversal.
|
||||||
///
|
///
|
||||||
@ -116,3 +119,80 @@ pub trait TypeVisitor<I: Interner>: Sized {
|
|||||||
p.super_visit_with(self)
|
p.super_visit_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Traversal implementations.
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>, U: TypeVisitable<I>> TypeVisitable<I> for (T, U) {
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
self.0.visit_with(visitor)?;
|
||||||
|
self.1.visit_with(visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, A: TypeVisitable<I>, B: TypeVisitable<I>, C: TypeVisitable<I>> TypeVisitable<I>
|
||||||
|
for (A, B, C)
|
||||||
|
{
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
self.0.visit_with(visitor)?;
|
||||||
|
self.1.visit_with(visitor)?;
|
||||||
|
self.2.visit_with(visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Option<T> {
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
match self {
|
||||||
|
Some(v) => v.visit_with(visitor),
|
||||||
|
None => ControlFlow::Continue(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for Result<T, E> {
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
match self {
|
||||||
|
Ok(v) => v.visit_with(visitor),
|
||||||
|
Err(e) => e.visit_with(visitor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Lrc<T> {
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
(**self).visit_with(visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<T> {
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
(**self).visit_with(visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Vec<T> {
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
self.iter().try_for_each(|t| t.visit_with(visitor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general
|
||||||
|
// case, because we can't return a new slice. But note that there are a couple
|
||||||
|
// of trivial impls of `TypeFoldable` for specific slice types elsewhere.
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] {
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
self.iter().try_for_each(|t| t.visit_with(visitor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
self.iter().try_for_each(|t| t.visit_with(visitor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix, T> {
|
||||||
|
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
|
self.iter().try_for_each(|t| t.visit_with(visitor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user