Factor out Type traversal to a Visit trait
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 87e3454..5422681 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -27,6 +27,7 @@
 mod toposort;
 pub mod trivial;
 pub mod types;
+mod visit;
 
 use self::attrs::OtherAttrs;
 use self::discriminant::Discriminant;
diff --git a/syntax/types.rs b/syntax/types.rs
index 031dc08..196a1db 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -5,6 +5,7 @@
 use crate::syntax::resolve::Resolution;
 use crate::syntax::set::{OrderedSet, UnorderedSet};
 use crate::syntax::trivial::{self, TrivialReason};
+use crate::syntax::visit::{self, Visit};
 use crate::syntax::{
     toposort, Api, Atom, Enum, ExternType, Impl, Lifetimes, Pair, Struct, Type, TypeAlias,
 };
@@ -41,28 +42,16 @@
         let toposorted_structs = Vec::new();
 
         fn visit<'a>(all: &mut OrderedSet<&'a Type>, ty: &'a Type) {
-            all.insert(ty);
-            match ty {
-                Type::Ident(_) | Type::Str(_) | Type::Void(_) => {}
-                Type::RustBox(ty)
-                | Type::UniquePtr(ty)
-                | Type::SharedPtr(ty)
-                | Type::WeakPtr(ty)
-                | Type::CxxVector(ty)
-                | Type::RustVec(ty) => visit(all, &ty.inner),
-                Type::Ref(r) => visit(all, &r.inner),
-                Type::Ptr(p) => visit(all, &p.inner),
-                Type::Array(a) => visit(all, &a.inner),
-                Type::SliceRef(s) => visit(all, &s.inner),
-                Type::Fn(f) => {
-                    if let Some(ret) = &f.ret {
-                        visit(all, ret);
-                    }
-                    for arg in &f.args {
-                        visit(all, &arg.ty);
-                    }
+            struct CollectTypes<'s, 'a>(&'s mut OrderedSet<&'a Type>);
+
+            impl<'s, 'a> Visit<'a> for CollectTypes<'s, 'a> {
+                fn visit_type(&mut self, ty: &'a Type) {
+                    self.0.insert(ty);
+                    visit::visit_type(self, ty);
                 }
             }
+
+            CollectTypes(all).visit_type(ty);
         }
 
         let mut add_resolution = |name: &'a Pair, generics: &'a Lifetimes| {
diff --git a/syntax/visit.rs b/syntax/visit.rs
new file mode 100644
index 0000000..2f31378
--- /dev/null
+++ b/syntax/visit.rs
@@ -0,0 +1,34 @@
+use crate::syntax::Type;
+
+pub trait Visit<'a> {
+    fn visit_type(&mut self, ty: &'a Type) {
+        visit_type(self, ty);
+    }
+}
+
+pub fn visit_type<'a, V>(visitor: &mut V, ty: &'a Type)
+where
+    V: Visit<'a> + ?Sized,
+{
+    match ty {
+        Type::Ident(_) | Type::Str(_) | Type::Void(_) => {}
+        Type::RustBox(ty)
+        | Type::UniquePtr(ty)
+        | Type::SharedPtr(ty)
+        | Type::WeakPtr(ty)
+        | Type::CxxVector(ty)
+        | Type::RustVec(ty) => visitor.visit_type(&ty.inner),
+        Type::Ref(r) => visitor.visit_type(&r.inner),
+        Type::Ptr(p) => visitor.visit_type(&p.inner),
+        Type::Array(a) => visitor.visit_type(&a.inner),
+        Type::SliceRef(s) => visitor.visit_type(&s.inner),
+        Type::Fn(fun) => {
+            if let Some(ret) = &fun.ret {
+                visitor.visit_type(ret);
+            }
+            for arg in &fun.args {
+                visitor.visit_type(&arg.ty);
+            }
+        }
+    }
+}