mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Uplift TypeVisitableExt into rustc_type_ir
This commit is contained in:
parent
bc1b9e0e9a
commit
f4e886323c
@ -35,6 +35,16 @@ impl<'tcx> IntoKind for Const<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> rustc_type_ir::visit::Flags for Const<'tcx> {
|
||||||
|
fn flags(&self) -> TypeFlags {
|
||||||
|
self.0.flags
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
|
||||||
|
self.0.outer_exclusive_binder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> ConstTy<TyCtxt<'tcx>> for Const<'tcx> {
|
impl<'tcx> ConstTy<TyCtxt<'tcx>> for Const<'tcx> {
|
||||||
fn ty(self) -> Ty<'tcx> {
|
fn ty(self) -> Ty<'tcx> {
|
||||||
self.ty()
|
self.ty()
|
||||||
@ -63,11 +73,13 @@ impl<'tcx> Const<'tcx> {
|
|||||||
self.0.kind
|
self.0.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(compiler-errors): Think about removing this.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn flags(self) -> TypeFlags {
|
pub fn flags(self) -> TypeFlags {
|
||||||
self.0.flags
|
self.0.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(compiler-errors): Think about removing this.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
|
pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
|
||||||
self.0.outer_exclusive_binder
|
self.0.outer_exclusive_binder
|
||||||
|
@ -88,6 +88,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||||||
type Term = ty::Term<'tcx>;
|
type Term = ty::Term<'tcx>;
|
||||||
|
|
||||||
type Binder<T> = Binder<'tcx, T>;
|
type Binder<T> = Binder<'tcx, T>;
|
||||||
|
type BoundVars = &'tcx List<ty::BoundVariableKind>;
|
||||||
|
type BoundVar = ty::BoundVariableKind;
|
||||||
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
||||||
|
|
||||||
type Ty = Ty<'tcx>;
|
type Ty = Ty<'tcx>;
|
||||||
@ -151,6 +153,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||||||
) -> Self::Const {
|
) -> Self::Const {
|
||||||
Const::new_bound(self, debruijn, var, ty)
|
Const::new_bound(self, debruijn, var, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expect_error_or_delayed_bug() {
|
||||||
|
let has_errors = ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs());
|
||||||
|
assert!(has_errors.is_some());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
|
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
|
||||||
|
@ -503,6 +503,16 @@ impl<'tcx> IntoKind for Ty<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> rustc_type_ir::visit::Flags for Ty<'tcx> {
|
||||||
|
fn flags(&self) -> TypeFlags {
|
||||||
|
self.0.flags
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outer_exclusive_binder(&self) -> DebruijnIndex {
|
||||||
|
self.0.outer_exclusive_binder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl EarlyParamRegion {
|
impl EarlyParamRegion {
|
||||||
/// Does this early bound region have a name? Early bound regions normally
|
/// Does this early bound region have a name? Early bound regions normally
|
||||||
/// always have names except when using anonymous lifetimes (`'_`).
|
/// always have names except when using anonymous lifetimes (`'_`).
|
||||||
|
@ -29,6 +29,16 @@ pub struct Predicate<'tcx>(
|
|||||||
pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
|
pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> {
|
||||||
|
fn flags(&self) -> TypeFlags {
|
||||||
|
self.0.flags
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outer_exclusive_binder(&self) -> ty::DebruijnIndex {
|
||||||
|
self.0.outer_exclusive_binder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Predicate<'tcx> {
|
impl<'tcx> Predicate<'tcx> {
|
||||||
/// Gets the inner `ty::Binder<'tcx, PredicateKind<'tcx>>`.
|
/// Gets the inner `ty::Binder<'tcx, PredicateKind<'tcx>>`.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -36,11 +46,13 @@ impl<'tcx> Predicate<'tcx> {
|
|||||||
self.0.internee
|
self.0.internee
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(compiler-errors): Think about removing this.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn flags(self) -> TypeFlags {
|
pub fn flags(self) -> TypeFlags {
|
||||||
self.0.flags
|
self.0.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(compiler-errors): Think about removing this.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn outer_exclusive_binder(self) -> DebruijnIndex {
|
pub fn outer_exclusive_binder(self) -> DebruijnIndex {
|
||||||
self.0.outer_exclusive_binder
|
self.0.outer_exclusive_binder
|
||||||
|
@ -26,6 +26,19 @@ impl<'tcx> rustc_type_ir::IntoKind for Region<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> rustc_type_ir::visit::Flags for Region<'tcx> {
|
||||||
|
fn flags(&self) -> TypeFlags {
|
||||||
|
self.type_flags()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outer_exclusive_binder(&self) -> ty::DebruijnIndex {
|
||||||
|
match **self {
|
||||||
|
ty::ReBound(debruijn, _) => debruijn.shifted_in(1),
|
||||||
|
_ => ty::INNERMOST,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Region<'tcx> {
|
impl<'tcx> Region<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_early_param(
|
pub fn new_early_param(
|
||||||
|
@ -942,6 +942,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx, T> rustc_type_ir::BoundVars<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
|
||||||
|
fn bound_vars(&self) -> &'tcx List<ty::BoundVariableKind> {
|
||||||
|
self.bound_vars
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_no_bound_vars(&self) -> bool {
|
||||||
|
self.bound_vars.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx, T> Binder<'tcx, T> {
|
impl<'tcx, T> Binder<'tcx, T> {
|
||||||
/// Skips the binder and returns the "bound" value. This is a
|
/// Skips the binder and returns the "bound" value. This is a
|
||||||
/// risky thing to do because it's easy to get confused about
|
/// risky thing to do because it's easy to get confused about
|
||||||
@ -1808,6 +1818,7 @@ impl<'tcx> Ty<'tcx> {
|
|||||||
self.0.0
|
self.0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(compiler-errors): Think about removing this.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn flags(self) -> TypeFlags {
|
pub fn flags(self) -> TypeFlags {
|
||||||
self.0.0.flags
|
self.0.0.flags
|
||||||
|
@ -1320,6 +1320,7 @@ impl<'tcx> Ty<'tcx> {
|
|||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(compiler-errors): Think about removing this.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
|
pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
|
||||||
self.0.outer_exclusive_binder
|
self.0.outer_exclusive_binder
|
||||||
|
@ -1,140 +1,10 @@
|
|||||||
use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
|
use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
|
||||||
use rustc_errors::ErrorGuaranteed;
|
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::sso::SsoHashSet;
|
use rustc_data_structures::sso::SsoHashSet;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||||
|
|
||||||
pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
|
|
||||||
/// Returns `true` if `self` has any late-bound regions that are either
|
|
||||||
/// bound by `binder` or bound by some binder outside of `binder`.
|
|
||||||
/// If `binder` is `ty::INNERMOST`, this indicates whether
|
|
||||||
/// there are any late-bound regions that appear free.
|
|
||||||
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
|
|
||||||
self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if this type has any regions that escape `binder` (and
|
|
||||||
/// hence are not bound by it).
|
|
||||||
fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
|
|
||||||
self.has_vars_bound_at_or_above(binder.shifted_in(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return `true` if this type has regions that are not a part of the type.
|
|
||||||
/// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)`
|
|
||||||
/// would return `true`. The latter can occur when traversing through the
|
|
||||||
/// former.
|
|
||||||
///
|
|
||||||
/// See [`HasEscapingVarsVisitor`] for more information.
|
|
||||||
fn has_escaping_bound_vars(&self) -> bool {
|
|
||||||
self.has_vars_bound_at_or_above(ty::INNERMOST)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_type_flags(&self, flags: TypeFlags) -> bool {
|
|
||||||
let res =
|
|
||||||
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
|
|
||||||
trace!(?self, ?flags, ?res, "has_type_flags");
|
|
||||||
res
|
|
||||||
}
|
|
||||||
fn has_projections(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
|
||||||
}
|
|
||||||
fn has_inherent_projections(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_INHERENT)
|
|
||||||
}
|
|
||||||
fn has_opaque_types(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
|
||||||
}
|
|
||||||
fn has_coroutines(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_COROUTINE)
|
|
||||||
}
|
|
||||||
fn references_error(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_ERROR)
|
|
||||||
}
|
|
||||||
fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
|
|
||||||
if self.references_error() {
|
|
||||||
// We must include lint errors and delayed bugs here.
|
|
||||||
if let Some(reported) =
|
|
||||||
ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs())
|
|
||||||
{
|
|
||||||
Err(reported)
|
|
||||||
} else {
|
|
||||||
bug!("expected some kind of error in `error_reported`");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn has_non_region_param(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM)
|
|
||||||
}
|
|
||||||
fn has_infer_regions(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_RE_INFER)
|
|
||||||
}
|
|
||||||
fn has_infer_types(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_INFER)
|
|
||||||
}
|
|
||||||
fn has_non_region_infer(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER)
|
|
||||||
}
|
|
||||||
fn has_infer(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_INFER)
|
|
||||||
}
|
|
||||||
fn has_placeholders(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_PLACEHOLDER)
|
|
||||||
}
|
|
||||||
fn has_non_region_placeholders(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER)
|
|
||||||
}
|
|
||||||
fn has_param(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_PARAM)
|
|
||||||
}
|
|
||||||
/// "Free" regions in this context means that it has any region
|
|
||||||
/// that is not (a) erased or (b) late-bound.
|
|
||||||
fn has_free_regions(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_erased_regions(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_RE_ERASED)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// True if there are any un-erased free regions.
|
|
||||||
fn has_erasable_regions(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates whether this value references only 'global'
|
|
||||||
/// generic parameters that are the same regardless of what fn we are
|
|
||||||
/// in. This is used for caching.
|
|
||||||
fn is_global(&self) -> bool {
|
|
||||||
!self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// True if there are any late-bound regions
|
|
||||||
fn has_bound_regions(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_RE_BOUND)
|
|
||||||
}
|
|
||||||
/// True if there are any late-bound non-region variables
|
|
||||||
fn has_non_region_bound_vars(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_BOUND_VARS - TypeFlags::HAS_RE_BOUND)
|
|
||||||
}
|
|
||||||
/// True if there are any bound variables
|
|
||||||
fn has_bound_vars(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_BOUND_VARS)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates whether this value still has parameters/placeholders/inference variables
|
|
||||||
/// which could be replaced later, in a way that would change the results of `impl`
|
|
||||||
/// specialization.
|
|
||||||
fn still_further_specializable(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitableExt<'tcx> for T {}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Region folder
|
// Region folder
|
||||||
@ -370,185 +240,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
|
||||||
struct FoundEscapingVars;
|
|
||||||
|
|
||||||
/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
|
|
||||||
/// bound region or a bound type.
|
|
||||||
///
|
|
||||||
/// So, for example, consider a type like the following, which has two binders:
|
|
||||||
///
|
|
||||||
/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
|
|
||||||
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
|
|
||||||
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope
|
|
||||||
///
|
|
||||||
/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
|
|
||||||
/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
|
|
||||||
/// fn type*, that type has an escaping region: `'a`.
|
|
||||||
///
|
|
||||||
/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
|
|
||||||
/// we already use the term "free var". It refers to the regions or types that we use to represent
|
|
||||||
/// bound regions or type params on a fn definition while we are type checking its body.
|
|
||||||
///
|
|
||||||
/// To clarify, conceptually there is no particular difference between
|
|
||||||
/// an "escaping" var and a "free" var. However, there is a big
|
|
||||||
/// difference in practice. Basically, when "entering" a binding
|
|
||||||
/// level, one is generally required to do some sort of processing to
|
|
||||||
/// a bound var, such as replacing it with a fresh/placeholder
|
|
||||||
/// var, or making an entry in the environment to represent the
|
|
||||||
/// scope to which it is attached, etc. An escaping var represents
|
|
||||||
/// a bound var for which this processing has not yet been done.
|
|
||||||
struct HasEscapingVarsVisitor {
|
|
||||||
/// Anything bound by `outer_index` or "above" is escaping.
|
|
||||||
outer_index: ty::DebruijnIndex,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasEscapingVarsVisitor {
|
|
||||||
type BreakTy = FoundEscapingVars;
|
|
||||||
|
|
||||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
|
||||||
&mut self,
|
|
||||||
t: &Binder<'tcx, T>,
|
|
||||||
) -> ControlFlow<Self::BreakTy> {
|
|
||||||
self.outer_index.shift_in(1);
|
|
||||||
let result = t.super_visit_with(self);
|
|
||||||
self.outer_index.shift_out(1);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
// If the outer-exclusive-binder is *strictly greater* than
|
|
||||||
// `outer_index`, that means that `t` contains some content
|
|
||||||
// bound at `outer_index` or above (because
|
|
||||||
// `outer_exclusive_binder` is always 1 higher than the
|
|
||||||
// content in `t`). Therefore, `t` has some escaping vars.
|
|
||||||
if t.outer_exclusive_binder() > self.outer_index {
|
|
||||||
ControlFlow::Break(FoundEscapingVars)
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
// If the region is bound by `outer_index` or anything outside
|
|
||||||
// of outer index, then it escapes the binders we have
|
|
||||||
// visited.
|
|
||||||
if r.bound_at_or_above_binder(self.outer_index) {
|
|
||||||
ControlFlow::Break(FoundEscapingVars)
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
// If the outer-exclusive-binder is *strictly greater* than
|
|
||||||
// `outer_index`, that means that `ct` contains some content
|
|
||||||
// bound at `outer_index` or above (because
|
|
||||||
// `outer_exclusive_binder` is always 1 higher than the
|
|
||||||
// content in `t`). Therefore, `t` has some escaping vars.
|
|
||||||
if ct.outer_exclusive_binder() > self.outer_index {
|
|
||||||
ControlFlow::Break(FoundEscapingVars)
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
if predicate.outer_exclusive_binder() > self.outer_index {
|
|
||||||
ControlFlow::Break(FoundEscapingVars)
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
|
||||||
struct FoundFlags;
|
|
||||||
|
|
||||||
// FIXME: Optimize for checking for infer flags
|
|
||||||
struct HasTypeFlagsVisitor {
|
|
||||||
flags: ty::TypeFlags,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for HasTypeFlagsVisitor {
|
|
||||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.flags.fmt(fmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: this visitor traverses values down to the level of
|
|
||||||
// `Ty`/`Const`/`Predicate`, but not within those types. This is because the
|
|
||||||
// type flags at the outer layer are enough. So it's faster than it first
|
|
||||||
// looks, particular for `Ty`/`Predicate` where it's just a field access.
|
|
||||||
//
|
|
||||||
// N.B. The only case where this isn't totally true is binders, which also
|
|
||||||
// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that
|
|
||||||
// are present, regardless of whether those bound variables are used. This
|
|
||||||
// is important for anonymization of binders in `TyCtxt::erase_regions`. We
|
|
||||||
// specifically detect this case in `visit_binder`.
|
|
||||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
|
|
||||||
type BreakTy = FoundFlags;
|
|
||||||
|
|
||||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
|
||||||
&mut self,
|
|
||||||
t: &Binder<'tcx, T>,
|
|
||||||
) -> ControlFlow<Self::BreakTy> {
|
|
||||||
// If we're looking for the HAS_BINDER_VARS flag, check if the
|
|
||||||
// binder has vars. This won't be present in the binder's bound
|
|
||||||
// value, so we need to check here too.
|
|
||||||
if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() {
|
|
||||||
return ControlFlow::Break(FoundFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
t.super_visit_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
// Note: no `super_visit_with` call.
|
|
||||||
let flags = t.flags();
|
|
||||||
if flags.intersects(self.flags) {
|
|
||||||
ControlFlow::Break(FoundFlags)
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
// Note: no `super_visit_with` call, as usual for `Region`.
|
|
||||||
let flags = r.type_flags();
|
|
||||||
if flags.intersects(self.flags) {
|
|
||||||
ControlFlow::Break(FoundFlags)
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
// Note: no `super_visit_with` call.
|
|
||||||
if c.flags().intersects(self.flags) {
|
|
||||||
ControlFlow::Break(FoundFlags)
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
// Note: no `super_visit_with` call.
|
|
||||||
if predicate.flags().intersects(self.flags) {
|
|
||||||
ControlFlow::Break(FoundFlags)
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Collects all the late-bound regions at the innermost binding level
|
/// Collects all the late-bound regions at the innermost binding level
|
||||||
/// into a hash set.
|
/// into a hash set.
|
||||||
struct LateBoundRegionsCollector {
|
struct LateBoundRegionsCollector {
|
||||||
|
7
compiler/rustc_type_ir/src/binder.rs
Normal file
7
compiler/rustc_type_ir/src/binder.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use crate::Interner;
|
||||||
|
|
||||||
|
pub trait BoundVars<I: Interner> {
|
||||||
|
fn bound_vars(&self) -> I::BoundVars;
|
||||||
|
|
||||||
|
fn has_no_bound_vars(&self) -> bool;
|
||||||
|
}
|
@ -3,8 +3,8 @@ use std::fmt::Debug;
|
|||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BoundVar, CanonicalVarInfo, ConstKind, DebruijnIndex, DebugWithInfcx, RegionKind, TyKind,
|
BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebruijnIndex, DebugWithInfcx, RegionKind,
|
||||||
UniverseIndex,
|
TyKind, UniverseIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Interner: Sized {
|
pub trait Interner: Sized {
|
||||||
@ -19,7 +19,10 @@ pub trait Interner: Sized {
|
|||||||
type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Ord;
|
type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type Term: Copy + Debug + Hash + Ord;
|
type Term: Copy + Debug + Hash + Ord;
|
||||||
|
|
||||||
type Binder<T>;
|
type Binder<T>: BoundVars<Self>;
|
||||||
|
type BoundVars: IntoIterator<Item = Self::BoundVar>;
|
||||||
|
type BoundVar;
|
||||||
|
|
||||||
type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
|
type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
|
||||||
|
|
||||||
// Kinds of tys
|
// Kinds of tys
|
||||||
@ -86,6 +89,9 @@ pub trait Interner: Sized {
|
|||||||
fn mk_bound_ty(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Ty;
|
fn mk_bound_ty(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Ty;
|
||||||
fn mk_bound_region(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Region;
|
fn mk_bound_region(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Region;
|
||||||
fn mk_bound_const(self, debruijn: DebruijnIndex, var: BoundVar, ty: Self::Ty) -> Self::Const;
|
fn mk_bound_const(self, debruijn: DebruijnIndex, var: BoundVar, ty: Self::Ty) -> Self::Const;
|
||||||
|
|
||||||
|
/// Assert that an error has been delayed or emitted.
|
||||||
|
fn expect_error_or_delayed_bug();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Common capabilities of placeholder kinds
|
/// Common capabilities of placeholder kinds
|
||||||
|
@ -30,6 +30,7 @@ pub mod visit;
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
mod binder;
|
||||||
mod canonical;
|
mod canonical;
|
||||||
mod const_kind;
|
mod const_kind;
|
||||||
mod debug;
|
mod debug;
|
||||||
@ -39,6 +40,7 @@ mod interner;
|
|||||||
mod predicate_kind;
|
mod predicate_kind;
|
||||||
mod region_kind;
|
mod region_kind;
|
||||||
|
|
||||||
|
pub use binder::*;
|
||||||
pub use canonical::*;
|
pub use canonical::*;
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub use codec::*;
|
pub use codec::*;
|
||||||
|
@ -45,8 +45,7 @@ use rustc_index::{Idx, IndexVec};
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use crate::Interner;
|
use crate::{self as ty, BoundVars, Interner, IntoKind, Lrc, TypeFlags};
|
||||||
use crate::Lrc;
|
|
||||||
|
|
||||||
/// 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.
|
||||||
@ -200,3 +199,393 @@ impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix
|
|||||||
self.iter().try_for_each(|t| t.visit_with(visitor))
|
self.iter().try_for_each(|t| t.visit_with(visitor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Flags {
|
||||||
|
fn flags(&self) -> TypeFlags;
|
||||||
|
fn outer_exclusive_binder(&self) -> ty::DebruijnIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {
|
||||||
|
fn has_type_flags(&self, flags: TypeFlags) -> bool;
|
||||||
|
|
||||||
|
/// Returns `true` if `self` has any late-bound regions that are either
|
||||||
|
/// bound by `binder` or bound by some binder outside of `binder`.
|
||||||
|
/// If `binder` is `ty::INNERMOST`, this indicates whether
|
||||||
|
/// there are any late-bound regions that appear free.
|
||||||
|
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool;
|
||||||
|
|
||||||
|
/// Returns `true` if this type has any regions that escape `binder` (and
|
||||||
|
/// hence are not bound by it).
|
||||||
|
fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
|
||||||
|
self.has_vars_bound_at_or_above(binder.shifted_in(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return `true` if this type has regions that are not a part of the type.
|
||||||
|
/// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)`
|
||||||
|
/// would return `true`. The latter can occur when traversing through the
|
||||||
|
/// former.
|
||||||
|
///
|
||||||
|
/// See [`HasEscapingVarsVisitor`] for more information.
|
||||||
|
fn has_escaping_bound_vars(&self) -> bool {
|
||||||
|
self.has_vars_bound_at_or_above(ty::INNERMOST)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_projections(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_inherent_projections(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_TY_INHERENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_opaque_types(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_coroutines(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_TY_COROUTINE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn references_error(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_reported(&self) -> Result<(), I::ErrorGuaranteed>;
|
||||||
|
|
||||||
|
fn has_non_region_param(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_infer_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_RE_INFER)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_infer_types(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_TY_INFER)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_non_region_infer(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_infer(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_INFER)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_placeholders(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_PLACEHOLDER)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_non_region_placeholders(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_param(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_PARAM)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "Free" regions in this context means that it has any region
|
||||||
|
/// that is not (a) erased or (b) late-bound.
|
||||||
|
fn has_free_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_erased_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_RE_ERASED)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True if there are any un-erased free regions.
|
||||||
|
fn has_erasable_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates whether this value references only 'global'
|
||||||
|
/// generic parameters that are the same regardless of what fn we are
|
||||||
|
/// in. This is used for caching.
|
||||||
|
fn is_global(&self) -> bool {
|
||||||
|
!self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True if there are any late-bound regions
|
||||||
|
fn has_bound_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_RE_BOUND)
|
||||||
|
}
|
||||||
|
/// True if there are any late-bound non-region variables
|
||||||
|
fn has_non_region_bound_vars(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_BOUND_VARS - TypeFlags::HAS_RE_BOUND)
|
||||||
|
}
|
||||||
|
/// True if there are any bound variables
|
||||||
|
fn has_bound_vars(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_BOUND_VARS)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates whether this value still has parameters/placeholders/inference variables
|
||||||
|
/// which could be replaced later, in a way that would change the results of `impl`
|
||||||
|
/// specialization.
|
||||||
|
fn still_further_specializable(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: TypeVisitable<I>> TypeVisitableExt<I> for T
|
||||||
|
where
|
||||||
|
I::Ty: Flags,
|
||||||
|
I::Region: Flags,
|
||||||
|
I::Const: Flags,
|
||||||
|
I::Predicate: Flags,
|
||||||
|
{
|
||||||
|
fn has_type_flags(&self, flags: TypeFlags) -> bool {
|
||||||
|
let res =
|
||||||
|
self.visit_with(&mut HasTypeFlagsVisitor { flags }) == ControlFlow::Break(FoundFlags);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
|
||||||
|
self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_reported(&self) -> Result<(), I::ErrorGuaranteed> {
|
||||||
|
if self.references_error() {
|
||||||
|
if let ControlFlow::Break(guar) = self.visit_with(&mut HasErrorVisitor) {
|
||||||
|
Err(guar)
|
||||||
|
} else {
|
||||||
|
panic!("type flags said there was an error, but now there is not")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
struct FoundFlags;
|
||||||
|
|
||||||
|
// FIXME: Optimize for checking for infer flags
|
||||||
|
struct HasTypeFlagsVisitor {
|
||||||
|
flags: ty::TypeFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for HasTypeFlagsVisitor {
|
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.flags.fmt(fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this visitor traverses values down to the level of
|
||||||
|
// `Ty`/`Const`/`Predicate`, but not within those types. This is because the
|
||||||
|
// type flags at the outer layer are enough. So it's faster than it first
|
||||||
|
// looks, particular for `Ty`/`Predicate` where it's just a field access.
|
||||||
|
//
|
||||||
|
// N.B. The only case where this isn't totally true is binders, which also
|
||||||
|
// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that
|
||||||
|
// are present, regardless of whether those bound variables are used. This
|
||||||
|
// is important for anonymization of binders in `TyCtxt::erase_regions`. We
|
||||||
|
// specifically detect this case in `visit_binder`.
|
||||||
|
impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor
|
||||||
|
where
|
||||||
|
I::Ty: Flags,
|
||||||
|
I::Region: Flags,
|
||||||
|
I::Const: Flags,
|
||||||
|
I::Predicate: Flags,
|
||||||
|
{
|
||||||
|
type BreakTy = FoundFlags;
|
||||||
|
|
||||||
|
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> ControlFlow<Self::BreakTy>
|
||||||
|
where
|
||||||
|
I::Binder<T>: TypeSuperVisitable<I>,
|
||||||
|
{
|
||||||
|
// If we're looking for the HAS_BINDER_VARS flag, check if the
|
||||||
|
// binder has vars. This won't be present in the binder's bound
|
||||||
|
// value, so we need to check here too.
|
||||||
|
if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.has_no_bound_vars() {
|
||||||
|
return ControlFlow::Break(FoundFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.super_visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> {
|
||||||
|
// Note: no `super_visit_with` call.
|
||||||
|
let flags = t.flags();
|
||||||
|
if flags.intersects(self.flags) {
|
||||||
|
ControlFlow::Break(FoundFlags)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy> {
|
||||||
|
// Note: no `super_visit_with` call, as usual for `Region`.
|
||||||
|
let flags = r.flags();
|
||||||
|
if flags.intersects(self.flags) {
|
||||||
|
ControlFlow::Break(FoundFlags)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy> {
|
||||||
|
// Note: no `super_visit_with` call.
|
||||||
|
if c.flags().intersects(self.flags) {
|
||||||
|
ControlFlow::Break(FoundFlags)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_predicate(&mut self, predicate: I::Predicate) -> ControlFlow<Self::BreakTy> {
|
||||||
|
// Note: no `super_visit_with` call.
|
||||||
|
if predicate.flags().intersects(self.flags) {
|
||||||
|
ControlFlow::Break(FoundFlags)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
struct FoundEscapingVars;
|
||||||
|
|
||||||
|
/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
|
||||||
|
/// bound region or a bound type.
|
||||||
|
///
|
||||||
|
/// So, for example, consider a type like the following, which has two binders:
|
||||||
|
///
|
||||||
|
/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
|
||||||
|
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
|
||||||
|
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope
|
||||||
|
///
|
||||||
|
/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
|
||||||
|
/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
|
||||||
|
/// fn type*, that type has an escaping region: `'a`.
|
||||||
|
///
|
||||||
|
/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
|
||||||
|
/// we already use the term "free var". It refers to the regions or types that we use to represent
|
||||||
|
/// bound regions or type params on a fn definition while we are type checking its body.
|
||||||
|
///
|
||||||
|
/// To clarify, conceptually there is no particular difference between
|
||||||
|
/// an "escaping" var and a "free" var. However, there is a big
|
||||||
|
/// difference in practice. Basically, when "entering" a binding
|
||||||
|
/// level, one is generally required to do some sort of processing to
|
||||||
|
/// a bound var, such as replacing it with a fresh/placeholder
|
||||||
|
/// var, or making an entry in the environment to represent the
|
||||||
|
/// scope to which it is attached, etc. An escaping var represents
|
||||||
|
/// a bound var for which this processing has not yet been done.
|
||||||
|
struct HasEscapingVarsVisitor {
|
||||||
|
/// Anything bound by `outer_index` or "above" is escaping.
|
||||||
|
outer_index: ty::DebruijnIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor
|
||||||
|
where
|
||||||
|
I::Ty: Flags,
|
||||||
|
I::Region: Flags,
|
||||||
|
I::Const: Flags,
|
||||||
|
I::Predicate: Flags,
|
||||||
|
{
|
||||||
|
type BreakTy = FoundEscapingVars;
|
||||||
|
|
||||||
|
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> ControlFlow<Self::BreakTy>
|
||||||
|
where
|
||||||
|
I::Binder<T>: TypeSuperVisitable<I>,
|
||||||
|
{
|
||||||
|
self.outer_index.shift_in(1);
|
||||||
|
let result = t.super_visit_with(self);
|
||||||
|
self.outer_index.shift_out(1);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> {
|
||||||
|
// If the outer-exclusive-binder is *strictly greater* than
|
||||||
|
// `outer_index`, that means that `t` contains some content
|
||||||
|
// bound at `outer_index` or above (because
|
||||||
|
// `outer_exclusive_binder` is always 1 higher than the
|
||||||
|
// content in `t`). Therefore, `t` has some escaping vars.
|
||||||
|
if t.outer_exclusive_binder() > self.outer_index {
|
||||||
|
ControlFlow::Break(FoundEscapingVars)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy> {
|
||||||
|
// If the region is bound by `outer_index` or anything outside
|
||||||
|
// of outer index, then it escapes the binders we have
|
||||||
|
// visited.
|
||||||
|
if r.outer_exclusive_binder() > self.outer_index {
|
||||||
|
ControlFlow::Break(FoundEscapingVars)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_const(&mut self, ct: I::Const) -> ControlFlow<Self::BreakTy> {
|
||||||
|
// If the outer-exclusive-binder is *strictly greater* than
|
||||||
|
// `outer_index`, that means that `ct` contains some content
|
||||||
|
// bound at `outer_index` or above (because
|
||||||
|
// `outer_exclusive_binder` is always 1 higher than the
|
||||||
|
// content in `t`). Therefore, `t` has some escaping vars.
|
||||||
|
if ct.outer_exclusive_binder() > self.outer_index {
|
||||||
|
ControlFlow::Break(FoundEscapingVars)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_predicate(&mut self, predicate: I::Predicate) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if predicate.outer_exclusive_binder() > self.outer_index {
|
||||||
|
ControlFlow::Break(FoundEscapingVars)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HasErrorVisitor;
|
||||||
|
|
||||||
|
impl<I: Interner> TypeVisitor<I> for HasErrorVisitor
|
||||||
|
where
|
||||||
|
I::Ty: Flags,
|
||||||
|
I::Region: Flags,
|
||||||
|
I::Const: Flags,
|
||||||
|
I::Predicate: Flags,
|
||||||
|
{
|
||||||
|
type BreakTy = I::ErrorGuaranteed;
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, t: <I as Interner>::Ty) -> ControlFlow<Self::BreakTy>
|
||||||
|
where
|
||||||
|
<I as Interner>::Ty: TypeSuperVisitable<I>,
|
||||||
|
{
|
||||||
|
if let ty::Error(guar) = t.kind() {
|
||||||
|
ControlFlow::Break(guar)
|
||||||
|
} else {
|
||||||
|
t.super_visit_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_const(&mut self, c: <I as Interner>::Const) -> ControlFlow<Self::BreakTy>
|
||||||
|
where
|
||||||
|
<I as Interner>::Const: TypeSuperVisitable<I>,
|
||||||
|
{
|
||||||
|
if let ty::ConstKind::Error(guar) = c.kind() {
|
||||||
|
ControlFlow::Break(guar)
|
||||||
|
} else {
|
||||||
|
c.super_visit_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_region(&mut self, r: <I as Interner>::Region) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let ty::ReError(guar) = r.kind() {
|
||||||
|
ControlFlow::Break(guar)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user