Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/walk.rs')
-rw-r--r--crates/hir-ty/src/walk.rs147
1 files changed, 147 insertions, 0 deletions
diff --git a/crates/hir-ty/src/walk.rs b/crates/hir-ty/src/walk.rs
new file mode 100644
index 0000000000..c476894552
--- /dev/null
+++ b/crates/hir-ty/src/walk.rs
@@ -0,0 +1,147 @@
+//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and
+//! `Visit`).
+
+use chalk_ir::interner::HasInterner;
+
+use crate::{
+ AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, GenericArgData, Interner,
+ OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, WhereClause,
+};
+
+/// This allows walking structures that contain types to do something with those
+/// types, similar to Chalk's `Fold` trait.
+pub trait TypeWalk {
+ fn walk(&self, f: &mut impl FnMut(&Ty));
+}
+
+impl TypeWalk for Ty {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ match self.kind(Interner) {
+ TyKind::Alias(AliasTy::Projection(p_ty)) => {
+ for t in p_ty.substitution.iter(Interner) {
+ t.walk(f);
+ }
+ }
+ TyKind::Alias(AliasTy::Opaque(o_ty)) => {
+ for t in o_ty.substitution.iter(Interner) {
+ t.walk(f);
+ }
+ }
+ TyKind::Dyn(dyn_ty) => {
+ for p in dyn_ty.bounds.skip_binders().interned().iter() {
+ p.walk(f);
+ }
+ }
+ TyKind::Slice(ty)
+ | TyKind::Array(ty, _)
+ | TyKind::Ref(_, _, ty)
+ | TyKind::Raw(_, ty) => {
+ ty.walk(f);
+ }
+ TyKind::Function(fn_pointer) => {
+ fn_pointer.substitution.0.walk(f);
+ }
+ TyKind::Adt(_, substs)
+ | TyKind::FnDef(_, substs)
+ | TyKind::Tuple(_, substs)
+ | TyKind::OpaqueType(_, substs)
+ | TyKind::AssociatedType(_, substs)
+ | TyKind::Closure(.., substs) => {
+ substs.walk(f);
+ }
+ _ => {}
+ }
+ f(self);
+ }
+}
+
+impl<T: TypeWalk> TypeWalk for Vec<T> {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ for t in self {
+ t.walk(f);
+ }
+ }
+}
+
+impl TypeWalk for OpaqueTy {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ self.substitution.walk(f);
+ }
+}
+
+impl TypeWalk for ProjectionTy {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ self.substitution.walk(f);
+ }
+}
+
+impl TypeWalk for AliasTy {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ match self {
+ AliasTy::Projection(it) => it.walk(f),
+ AliasTy::Opaque(it) => it.walk(f),
+ }
+ }
+}
+
+impl TypeWalk for GenericArg {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ if let GenericArgData::Ty(ty) = &self.interned() {
+ ty.walk(f);
+ }
+ }
+}
+
+impl TypeWalk for Substitution {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ for t in self.iter(Interner) {
+ t.walk(f);
+ }
+ }
+}
+
+impl<T: TypeWalk + HasInterner<Interner = Interner>> TypeWalk for Binders<T> {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ self.skip_binders().walk(f);
+ }
+}
+
+impl TypeWalk for TraitRef {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ self.substitution.walk(f);
+ }
+}
+
+impl TypeWalk for WhereClause {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ match self {
+ WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
+ WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
+ _ => {}
+ }
+ }
+}
+
+impl TypeWalk for CallableSig {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ for t in self.params_and_return.iter() {
+ t.walk(f);
+ }
+ }
+}
+
+impl TypeWalk for AliasEq {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ self.ty.walk(f);
+ match &self.alias {
+ AliasTy::Projection(projection_ty) => projection_ty.walk(f),
+ AliasTy::Opaque(opaque) => opaque.walk(f),
+ }
+ }
+}
+
+impl TypeWalk for FnSubst<Interner> {
+ fn walk(&self, f: &mut impl FnMut(&Ty)) {
+ self.0.walk(f)
+ }
+}