Index: src/AST/Copy.hpp
===================================================================
--- src/AST/Copy.hpp	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
+++ src/AST/Copy.hpp	(revision d3aa64f1fa52252ca6f76dda4aaf32c039f504d5)
@@ -21,4 +21,6 @@
 #include "Stmt.hpp"
 #include "Type.hpp"
+#include <unordered_set>
+#include <unordered_map>
 
 namespace ast {
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
+++ src/AST/Pass.hpp	(revision d3aa64f1fa52252ca6f76dda4aaf32c039f504d5)
@@ -266,4 +266,8 @@
 
 /// Keep track of the polymorphic const TypeSubstitution * env for the current expression
+
+/// marker to force shallow copies in pass visit
+struct PureVisitor {};
+
 struct WithConstTypeSubstitution {
 	const TypeSubstitution * env = nullptr;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
+++ src/AST/Pass.impl.hpp	(revision d3aa64f1fa52252ca6f76dda4aaf32c039f504d5)
@@ -21,4 +21,5 @@
 
 #include "AST/TypeSubstitution.hpp"
+// #include "AST/Copy.hpp"
 
 #define VISIT_START( node ) \
@@ -57,4 +58,7 @@
 
 namespace ast {
+	template<typename node_t>
+	node_t * shallowCopy( const node_t * node );
+
 	namespace __pass {
 		// Check if this is either a null pointer or a pointer to an empty container
@@ -62,4 +66,9 @@
 		static inline bool empty( T * ptr ) {
 			return !ptr || ptr->empty();
+		}
+
+		template< typename core_t, typename node_t >
+		static inline node_t* mutate(const node_t *node) {
+			return std::is_base_of<PureVisitor, core_t>::value ? ::ast::shallowCopy(node) : ::ast::mutate(node);
 		}
 
@@ -320,5 +329,6 @@
 
 		if( __pass::differs(old_val, new_val) ) {
-			auto new_parent = mutate(parent);
+			// auto new_parent = mutate(parent);
+			auto new_parent = __pass::mutate<core_t>(parent);
 			new_parent->*child = new_val;
 			parent = new_parent;
@@ -334,5 +344,5 @@
 			if ( node->forall.empty() ) return;
 
-			node_t * mut = mutate( node );
+			node_t * mut = __pass::mutate<core_t>( node );
 			mut->forall = subs->clone( node->forall, *this );
 			node = mut;
@@ -894,5 +904,5 @@
 
 		if(mutated) {
-			auto n = mutate(node);
+			auto n = __pass::mutate<core_t>(node);
 			n->clauses = std::move( new_clauses );
 			node = n;
@@ -904,5 +914,5 @@
 			auto nval = call_accept( node->field ); \
 			if(nval != node->field ) { \
-				auto nparent = mutate(node); \
+				auto nparent = __pass::mutate<core_t>(node); \
 				nparent->field = nval; \
 				node = nparent; \
@@ -1610,5 +1620,5 @@
 
 		if(mutated) {
-			auto n = mutate(node);
+			auto n = __pass::mutate<core_t>(node);
 			n->associations = std::move( new_kids );
 			node = n;
@@ -1940,5 +1950,5 @@
 			}
 			if (mutated) {
-				auto new_node = mutate( node );
+				auto new_node = __pass::mutate<core_t>( node );
 				new_node->typeEnv.swap( new_map );
 				node = new_node;
@@ -1956,5 +1966,5 @@
 			}
 			if (mutated) {
-				auto new_node = mutate( node );
+				auto new_node = __pass::mutate<core_t>( node );
 				new_node->varEnv.swap( new_map );
 				node = new_node;
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
+++ src/AST/Pass.proto.hpp	(revision d3aa64f1fa52252ca6f76dda4aaf32c039f504d5)
@@ -22,4 +22,6 @@
 template<typename core_t>
 class Pass;
+
+struct PureVisitor;
 
 namespace __pass {
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
+++ src/AST/TypeSubstitution.hpp	(revision d3aa64f1fa52252ca6f76dda4aaf32c039f504d5)
@@ -159,5 +159,5 @@
 
 // definitition must happen after PassVisitor is included so that WithGuards can be used
-struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
+struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter>, public PureVisitor {
 		static size_t traceId;
 
@@ -187,5 +187,6 @@
 	assert( input );
 	Pass<Substituter> sub( *this, false );
-	input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
+//	input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
+	input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
 	return { input, sub.core.subCount };
 }
@@ -195,5 +196,6 @@
 	assert( input );
 	Pass<Substituter> sub( *this, true );
-	input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
+//	input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
+	input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
 	return { input, sub.core.subCount };
 }
