1 //! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and
2 //! `Visit`).
3 
4 use chalk_ir::interner::HasInterner;
5 
6 use crate::{
7     AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, GenericArgData, Interner,
8     OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, WhereClause,
9 };
10 
11 /// This allows walking structures that contain types to do something with those
12 /// types, similar to Chalk's `Fold` trait.
13 pub trait TypeWalk {
walk(&self, f: &mut impl FnMut(&Ty))14     fn walk(&self, f: &mut impl FnMut(&Ty));
15 }
16 
17 impl TypeWalk for Ty {
walk(&self, f: &mut impl FnMut(&Ty))18     fn walk(&self, f: &mut impl FnMut(&Ty)) {
19         match self.kind(Interner) {
20             TyKind::Alias(AliasTy::Projection(p_ty)) => {
21                 for t in p_ty.substitution.iter(Interner) {
22                     t.walk(f);
23                 }
24             }
25             TyKind::Alias(AliasTy::Opaque(o_ty)) => {
26                 for t in o_ty.substitution.iter(Interner) {
27                     t.walk(f);
28                 }
29             }
30             TyKind::Dyn(dyn_ty) => {
31                 for p in dyn_ty.bounds.skip_binders().interned().iter() {
32                     p.walk(f);
33                 }
34             }
35             TyKind::Slice(ty)
36             | TyKind::Array(ty, _)
37             | TyKind::Ref(_, _, ty)
38             | TyKind::Raw(_, ty) => {
39                 ty.walk(f);
40             }
41             TyKind::Function(fn_pointer) => {
42                 fn_pointer.substitution.0.walk(f);
43             }
44             TyKind::Adt(_, substs)
45             | TyKind::FnDef(_, substs)
46             | TyKind::Tuple(_, substs)
47             | TyKind::OpaqueType(_, substs)
48             | TyKind::AssociatedType(_, substs)
49             | TyKind::Closure(.., substs) => {
50                 substs.walk(f);
51             }
52             _ => {}
53         }
54         f(self);
55     }
56 }
57 
58 impl<T: TypeWalk> TypeWalk for Vec<T> {
walk(&self, f: &mut impl FnMut(&Ty))59     fn walk(&self, f: &mut impl FnMut(&Ty)) {
60         for t in self {
61             t.walk(f);
62         }
63     }
64 }
65 
66 impl TypeWalk for OpaqueTy {
walk(&self, f: &mut impl FnMut(&Ty))67     fn walk(&self, f: &mut impl FnMut(&Ty)) {
68         self.substitution.walk(f);
69     }
70 }
71 
72 impl TypeWalk for ProjectionTy {
walk(&self, f: &mut impl FnMut(&Ty))73     fn walk(&self, f: &mut impl FnMut(&Ty)) {
74         self.substitution.walk(f);
75     }
76 }
77 
78 impl TypeWalk for AliasTy {
walk(&self, f: &mut impl FnMut(&Ty))79     fn walk(&self, f: &mut impl FnMut(&Ty)) {
80         match self {
81             AliasTy::Projection(it) => it.walk(f),
82             AliasTy::Opaque(it) => it.walk(f),
83         }
84     }
85 }
86 
87 impl TypeWalk for GenericArg {
walk(&self, f: &mut impl FnMut(&Ty))88     fn walk(&self, f: &mut impl FnMut(&Ty)) {
89         if let GenericArgData::Ty(ty) = &self.interned() {
90             ty.walk(f);
91         }
92     }
93 }
94 
95 impl TypeWalk for Substitution {
walk(&self, f: &mut impl FnMut(&Ty))96     fn walk(&self, f: &mut impl FnMut(&Ty)) {
97         for t in self.iter(Interner) {
98             t.walk(f);
99         }
100     }
101 }
102 
103 impl<T: TypeWalk + HasInterner<Interner = Interner>> TypeWalk for Binders<T> {
walk(&self, f: &mut impl FnMut(&Ty))104     fn walk(&self, f: &mut impl FnMut(&Ty)) {
105         self.skip_binders().walk(f);
106     }
107 }
108 
109 impl TypeWalk for TraitRef {
walk(&self, f: &mut impl FnMut(&Ty))110     fn walk(&self, f: &mut impl FnMut(&Ty)) {
111         self.substitution.walk(f);
112     }
113 }
114 
115 impl TypeWalk for WhereClause {
walk(&self, f: &mut impl FnMut(&Ty))116     fn walk(&self, f: &mut impl FnMut(&Ty)) {
117         match self {
118             WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
119             WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
120             _ => {}
121         }
122     }
123 }
124 
125 impl TypeWalk for CallableSig {
walk(&self, f: &mut impl FnMut(&Ty))126     fn walk(&self, f: &mut impl FnMut(&Ty)) {
127         for t in self.params_and_return.iter() {
128             t.walk(f);
129         }
130     }
131 }
132 
133 impl TypeWalk for AliasEq {
walk(&self, f: &mut impl FnMut(&Ty))134     fn walk(&self, f: &mut impl FnMut(&Ty)) {
135         self.ty.walk(f);
136         match &self.alias {
137             AliasTy::Projection(projection_ty) => projection_ty.walk(f),
138             AliasTy::Opaque(opaque) => opaque.walk(f),
139         }
140     }
141 }
142 
143 impl TypeWalk for FnSubst<Interner> {
walk(&self, f: &mut impl FnMut(&Ty))144     fn walk(&self, f: &mut impl FnMut(&Ty)) {
145         self.0.walk(f)
146     }
147 }
148