Also, I find the whole visitor pattern abstraction a little pointless in Rust. I can't help but feel that applying a visitor pattern is taking an idiosyncrasy of object oriented programming and forcing it into Rust. Basically abstraction for abstraction's sake. I'd much rather write a bunch of `visit_expr`, `visit_stmt` (really `type_check_expr`, `type_check_stmt`) functions that pattern match on the data. It's much more searchable, and condenses the information at the pass level and not the data structure level. I care much more about having all of my type checking methods in one place, than I care about having all of the transformations of `Expr` in one place. I suppose if you're doing a lot of passes over the same representation and you need to schedule them in an efficient way, a visitor pattern could work. But how often are you doing that? Maybe if you're writing an optimizer but more often than not I'm doing a transformation pass from one IR to another.
With that said I can sympathize with ASTs being a lot of boilerplate. It took a lot of typing to thread location data through my AST.