use std::fmt;
use std::ops::ControlFlow;
use std::sync::Arc;
pub use rustc_ast_ir::visit::VisitorResult;
pub use rustc_ast_ir::{try_visit, walk_visitable_list};
use rustc_index::{Idx, IndexVec};
use smallvec::SmallVec;
use thin_vec::ThinVec;
use crate::inherent::*;
use crate::{self as ty, Interner, TypeFlags};
pub trait TypeVisitable<I: Interner>: fmt::Debug {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
}
pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> {
fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
}
pub trait TypeVisitor<I: Interner>: Sized {
#[cfg(feature = "nightly")]
type Result: VisitorResult = ();
#[cfg(not(feature = "nightly"))]
type Result: VisitorResult;
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
t.super_visit_with(self)
}
fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
t.super_visit_with(self)
}
fn visit_region(&mut self, r: I::Region) -> Self::Result {
if let ty::ReError(guar) = r.kind() {
self.visit_error(guar)
} else {
Self::Result::output()
}
}
fn visit_const(&mut self, c: I::Const) -> Self::Result {
c.super_visit_with(self)
}
fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result {
p.super_visit_with(self)
}
fn visit_clauses(&mut self, c: I::Clauses) -> Self::Result {
c.super_visit_with(self)
}
fn visit_error(&mut self, _guar: I::ErrorGuaranteed) -> Self::Result {
Self::Result::output()
}
}
impl<I: Interner, T: TypeVisitable<I>, U: TypeVisitable<I>> TypeVisitable<I> for (T, U) {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
try_visit!(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) -> V::Result {
try_visit!(self.0.visit_with(visitor));
try_visit!(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) -> V::Result {
match self {
Some(v) => v.visit_with(visitor),
None => V::Result::output(),
}
}
}
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) -> V::Result {
match self {
Ok(v) => v.visit_with(visitor),
Err(e) => e.visit_with(visitor),
}
}
}
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Arc<T> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
(**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) -> V::Result {
(**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) -> V::Result {
walk_visitable_list!(visitor, self.iter());
V::Result::output()
}
}
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for ThinVec<T> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
walk_visitable_list!(visitor, self.iter());
V::Result::output()
}
}
impl<I: Interner, T: TypeVisitable<I>, const N: usize> TypeVisitable<I> for SmallVec<[T; N]> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
walk_visitable_list!(visitor, self.iter());
V::Result::output()
}
}
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
walk_visitable_list!(visitor, self.iter());
V::Result::output()
}
}
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
walk_visitable_list!(visitor, self.iter());
V::Result::output()
}
}
impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix, T> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
walk_visitable_list!(visitor, self.iter());
V::Result::output()
}
}
impl<I: Interner, T: TypeVisitable<I>, S> TypeVisitable<I> for indexmap::IndexSet<T, S> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
walk_visitable_list!(visitor, self.iter());
V::Result::output()
}
}
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;
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool;
fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
self.has_vars_bound_at_or_above(binder.shifted_in(1))
}
fn has_escaping_bound_vars(&self) -> bool {
self.has_vars_bound_at_or_above(ty::INNERMOST)
}
fn has_aliases(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_ALIAS)
}
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_CORO)
}
fn references_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_ERROR)
}
fn error_reported(&self) -> Result<(), I::ErrorGuaranteed>;
fn non_region_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_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_REGIONS)
}
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)
}
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)
}
fn has_erasable_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
}
fn is_global(&self) -> bool {
!self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
}
fn has_bound_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_BOUND)
}
fn has_non_region_bound_vars(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_BOUND_VARS - TypeFlags::HAS_RE_BOUND)
}
fn has_bound_vars(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_BOUND_VARS)
}
fn still_further_specializable(&self) -> bool {
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
}
fn has_non_region_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_NON_REGION_ERROR)
}
}
impl<I: Interner, T: TypeVisitable<I>> TypeVisitableExt<I> for T {
fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.visit_with(&mut HasTypeFlagsVisitor { flags }) == ControlFlow::Break(FoundFlags)
}
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder })
== ControlFlow::Break(FoundEscapingVars)
}
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(())
}
}
fn non_region_error_reported(&self) -> Result<(), I::ErrorGuaranteed> {
if self.has_non_region_error() {
if let ControlFlow::Break(guar) = self.visit_with(&mut HasErrorVisitor) {
Err(guar)
} else {
panic!("type flags said there was an non region error, but now there is not")
}
} else {
Ok(())
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
struct FoundFlags;
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)
}
}
impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
type Result = ControlFlow<FoundFlags>;
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
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: I::Ty) -> Self::Result {
if t.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::Continue(())
}
}
#[inline]
fn visit_region(&mut self, r: I::Region) -> Self::Result {
if r.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::Continue(())
}
}
#[inline]
fn visit_const(&mut self, c: I::Const) -> Self::Result {
if c.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::Continue(())
}
}
#[inline]
fn visit_predicate(&mut self, predicate: I::Predicate) -> Self::Result {
if predicate.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::Continue(())
}
}
#[inline]
fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result {
if clauses.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::Continue(())
}
}
#[inline]
fn visit_error(&mut self, _guar: <I as Interner>::ErrorGuaranteed) -> Self::Result {
if self.flags.intersects(TypeFlags::HAS_ERROR) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::Continue(())
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
struct FoundEscapingVars;
struct HasEscapingVarsVisitor {
outer_index: ty::DebruijnIndex,
}
impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor {
type Result = ControlFlow<FoundEscapingVars>;
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
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) -> Self::Result {
if t.outer_exclusive_binder() > self.outer_index {
ControlFlow::Break(FoundEscapingVars)
} else {
ControlFlow::Continue(())
}
}
#[inline]
fn visit_region(&mut self, r: I::Region) -> Self::Result {
if r.outer_exclusive_binder() > self.outer_index {
ControlFlow::Break(FoundEscapingVars)
} else {
ControlFlow::Continue(())
}
}
fn visit_const(&mut self, ct: I::Const) -> Self::Result {
if ct.outer_exclusive_binder() > self.outer_index {
ControlFlow::Break(FoundEscapingVars)
} else {
ControlFlow::Continue(())
}
}
#[inline]
fn visit_predicate(&mut self, predicate: I::Predicate) -> Self::Result {
if predicate.outer_exclusive_binder() > self.outer_index {
ControlFlow::Break(FoundEscapingVars)
} else {
ControlFlow::Continue(())
}
}
#[inline]
fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result {
if clauses.outer_exclusive_binder() > self.outer_index {
ControlFlow::Break(FoundEscapingVars)
} else {
ControlFlow::Continue(())
}
}
}
struct HasErrorVisitor;
impl<I: Interner> TypeVisitor<I> for HasErrorVisitor {
type Result = ControlFlow<I::ErrorGuaranteed>;
fn visit_error(&mut self, guar: <I as Interner>::ErrorGuaranteed) -> Self::Result {
ControlFlow::Break(guar)
}
}