Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions compiler/rustc_type_ir/src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ bitflags::bitflags! {
/// Does this have any `ReErased` regions?
const HAS_RE_ERASED = 1 << 21;

/// Does this have any regions of any kind?
const HAS_REGIONS = TypeFlags::HAS_FREE_REGIONS.bits()
Copy link
Copy Markdown
Member

@WaffleLapkin WaffleLapkin May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add has_regions to TypeVisitableExt too and then use it instead of .has_type_flags(TypeFlags::HAS_REGIONS)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

| TypeFlags::HAS_RE_BOUND.bits()
| TypeFlags::HAS_RE_ERASED.bits();

/// 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 = TypeFlags::HAS_TY_PARAM.bits()
Expand All @@ -139,7 +144,7 @@ bitflags::bitflags! {
/// Does this type have any coroutines in it?
const HAS_TY_CORO = 1 << 25;

/// Does this have have a `Bound(BoundVarIndexKind::Canonical, _)`?
/// Does this have a `Bound(BoundVarIndexKind::Canonical, _)`?
const HAS_CANONICAL_BOUND = 1 << 26;
}
}
Expand Down Expand Up @@ -192,7 +197,7 @@ impl<I: Interner> FlagComputation<I> {
}

fn add_flags(&mut self, flags: TypeFlags) {
self.flags = self.flags | flags;
self.flags |= flags;
}

/// indicates that `self` refers to something at binding level `binder`
Expand Down
44 changes: 15 additions & 29 deletions compiler/rustc_type_ir/src/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,6 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
/// default that does an "identity" fold. Implementations of these methods
/// often fall back to a `super_fold_with` method if the primary argument
/// doesn't satisfy a particular condition.
///
/// A blanket implementation of [`FallibleTypeFolder`] will defer to
/// the infallible methods of this trait to ensure that the two APIs
/// are coherent.
pub trait TypeFolder<I: Interner>: Sized {
fn cx(&self) -> I;

Expand Down Expand Up @@ -437,6 +433,10 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> {
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
}

fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
if c.has_vars_bound_at_or_above(self.current_index) { c.super_fold_with(self) } else { c }
}
}

pub fn shift_region<I: Interner>(cx: I, region: I::Region, amount: u32) -> I::Region {
Expand Down Expand Up @@ -477,10 +477,10 @@ where
/// Folds over the substructure of a type, visiting its component
/// types and all regions that occur *free* within it.
///
/// That is, function pointer types and trait object can introduce
/// new bound regions which are not visited by this visitors as
/// That is, function pointer types and trait objects can introduce
/// new bound regions which are not visited by this visitor as
/// they are not free; only regions that occur free will be
/// visited by `fld_r`.
/// visited by `fold_region_fn`.
pub struct RegionFolder<I, F> {
cx: I,

Expand All @@ -489,7 +489,7 @@ pub struct RegionFolder<I, F> {
/// binder, it is incremented (via `shift_in`).
current_index: ty::DebruijnIndex,

/// Callback invokes for each free region. The `DebruijnIndex`
/// Callback invoked for each free region. The `DebruijnIndex`
/// points to the binder *just outside* the ones we have passed
/// through.
fold_region_fn: F,
Expand Down Expand Up @@ -539,32 +539,18 @@ where
}

fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
if t.has_type_flags(
TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_RE_BOUND | TypeFlags::HAS_RE_ERASED,
) {
t.super_fold_with(self)
} else {
t
}
if t.has_type_flags(TypeFlags::HAS_REGIONS) { t.super_fold_with(self) } else { t }
}

fn fold_const(&mut self, ct: I::Const) -> I::Const {
if ct.has_type_flags(
TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_RE_BOUND | TypeFlags::HAS_RE_ERASED,
) {
ct.super_fold_with(self)
} else {
ct
}
if ct.has_type_flags(TypeFlags::HAS_REGIONS) { ct.super_fold_with(self) } else { ct }
}

fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
if p.has_type_flags(
TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_RE_BOUND | TypeFlags::HAS_RE_ERASED,
) {
p.super_fold_with(self)
} else {
p
}
if p.has_type_flags(TypeFlags::HAS_REGIONS) { p.super_fold_with(self) } else { p }
}

fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
if c.has_type_flags(TypeFlags::HAS_REGIONS) { c.super_fold_with(self) } else { c }
}
}
30 changes: 15 additions & 15 deletions compiler/rustc_type_ir/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub trait TypeVisitable<I: Interner>: fmt::Debug {
/// each field/element.
///
/// For types of interest (such as `Ty`), the implementation of this method
/// that calls a visitor method specifically for that type (such as
/// calls a visitor method specifically for that type (such as
/// `V::visit_ty`). This is where control transfers from `TypeVisitable` to
/// `TypeVisitor`.
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
Expand Down Expand Up @@ -102,8 +102,8 @@ pub trait TypeVisitor<I: Interner>: Sized {
t.super_visit_with(self)
}

// The default region visitor is a no-op because `Region` is non-recursive
// and has no `super_visit_with` method to call.
// `Region` is non-recursive so the default region visitor has no
// `super_visit_with` method to call.
fn visit_region(&mut self, r: I::Region) -> Self::Result {
if let ty::ReError(guar) = r.kind() {
self.visit_error(guar)
Expand Down Expand Up @@ -251,10 +251,10 @@ pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {
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.
/// Returns `true` if this type has regions that are not a part of the
/// type. For example, given a `for<'a> fn(&'a i32)` this function returns
/// `false`, while given a `fn(&'a i32)` it returns `true`. The latter can
/// occur when traversing through the former.
///
/// See [`HasEscapingVarsVisitor`] for more information.
fn has_escaping_bound_vars(&self) -> bool {
Expand Down Expand Up @@ -285,6 +285,10 @@ pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {
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)
}
Expand Down Expand Up @@ -363,9 +367,7 @@ pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {

impl<I: Interner, T: TypeVisitable<I>> TypeVisitableExt<I> for T {
fn has_type_flags(&self, flags: TypeFlags) -> bool {
let res =
self.visit_with(&mut HasTypeFlagsVisitor { flags }) == ControlFlow::Break(FoundFlags);
res
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo comparing with ControlFlow::Break(FoundFlags) is clearer, because it asserts that Break contains FoundFlags

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though FoundFlags is a unit type?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that has_vars_bound_at_or_above uses .is_break(). I was fixing the inconsistency and .is_break() seemed nicer.

self.visit_with(&mut HasTypeFlagsVisitor { flags }).is_break()
}

fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
Expand Down Expand Up @@ -438,8 +440,7 @@ impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
#[inline]
fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
// Note: no `super_visit_with` call.
let flags = t.flags();
if flags.intersects(self.flags) {
if t.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::Continue(())
Expand All @@ -449,8 +450,7 @@ impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
#[inline]
fn visit_region(&mut self, r: I::Region) -> Self::Result {
// Note: no `super_visit_with` call, as usual for `Region`.
let flags = r.flags();
if flags.intersects(self.flags) {
if r.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::Continue(())
Expand Down Expand Up @@ -571,7 +571,7 @@ impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor {
// `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.
// content in `ct`). Therefore, `ct` has some escaping vars.
if ct.outer_exclusive_binder() > self.outer_index {
ControlFlow::Break(FoundEscapingVars)
} else {
Expand Down
Loading