Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/Decl.hpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -101,7 +101,7 @@
 	ptr<Expr> bitfieldWidth;
 
-	ObjectDecl( const CodeLocation& loc, const std::string& name, Type* type, Init* init = nullptr,
-		Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, Expr* bitWd = nullptr,
-		std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {})
+	ObjectDecl( const CodeLocation & loc, const std::string & name, const Type * type, Init * init = nullptr,
+		Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, Expr * bitWd = nullptr,
+		std::vector< ptr<Attribute> > && attrs = {}, Function::Specs fs = {})
 	: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ),
 	  init( init ), bitfieldWidth( bitWd ) {}
Index: src/AST/DeclReplacer.cpp
===================================================================
--- src/AST/DeclReplacer.cpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/DeclReplacer.cpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -14,5 +14,5 @@
 //
 
-#error unimplemented
+#warning unimplemented
 
 // Local Variables: //
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/Expr.cpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -95,5 +95,4 @@
 	Type * addrType( const Type * type ) {
 		if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * >( type ) ) {
-			CV::Qualifiers quals = refType->qualifiers;
 			return new ReferenceType{ addrType( refType->base ), refType->qualifiers };
 		} else {
@@ -118,5 +117,5 @@
 				result = res;
 			} else {
-				SemanticError( loc, arg->result,
+				SemanticError( loc, arg->result.get(),
 					"Attempt to take address of non-lvalue expression: " );
 			}
@@ -283,7 +282,7 @@
 // --- ConstructorExpr
 
-ConstructorExpr::ConstructorExpr( const CodeLocation & loc, const Expr * call ) 
+ConstructorExpr::ConstructorExpr( const CodeLocation & loc, const Expr * call )
 : Expr( loc ), callExpr( call ) {
-	// allow resolver to type a constructor used as an expression if it has the same type as its 
+	// allow resolver to type a constructor used as an expression if it has the same type as its
 	// first argument
 	assert( callExpr );
@@ -310,5 +309,5 @@
 TupleIndexExpr::TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i )
 : Expr( loc ), tuple( t ), index( i ) {
-	const TupleType * type = strict_dynamic_cast< const TupleType * >( tuple->result );
+	const TupleType * type = strict_dynamic_cast< const TupleType * >( tuple->result.get() );
 	assertf( type->size() > index, "TupleIndexExpr index out of bounds: tuple size %d, requested "
 		"index %d in expr %s", type->size(), index, toString( tuple ).c_str() );
@@ -319,9 +318,9 @@
 // --- TupleAssignExpr
 
-TupleAssignExpr::TupleAssignExpr( 
-	const CodeLocation & loc, std::vector<ptr<Expr>> && assigns, 
+TupleAssignExpr::TupleAssignExpr(
+	const CodeLocation & loc, std::vector<ptr<Expr>> && assigns,
 	std::vector<ptr<ObjectDecl>> && tempDecls )
 : Expr( loc, Tuples::makeTupleType( assigns ) ), stmtExpr() {
-	// convert internally into a StmtExpr which contains the declarations and produces the tuple of 
+	// convert internally into a StmtExpr which contains the declarations and produces the tuple of
 	// the assignments
 	std::list<ptr<Stmt>> stmts;
@@ -337,5 +336,5 @@
 // --- StmtExpr
 
-StmtExpr::StmtExpr( const CodeLocation & loc, const CompoundStmt * ss ) 
+StmtExpr::StmtExpr( const CodeLocation & loc, const CompoundStmt * ss )
 : Expr( loc ), stmts( ss ), returnDecls(), dtors() { computeResult(); }
 
@@ -344,5 +343,5 @@
 	const std::list<ptr<Stmt>> & body = stmts->kids;
 	if ( ! returnDecls.empty() ) {
-		// prioritize return decl for result type, since if a return decl exists, then the StmtExpr 
+		// prioritize return decl for result type, since if a return decl exists, then the StmtExpr
 		// is currently in an intermediate state where the body will always give a void result type
 		result = returnDecls.front()->get_type();
@@ -360,11 +359,13 @@
 unsigned long long UniqueExpr::nextId = 0;
 
-UniqueExpr::UniqueExpr( const CodeLocation & loc, const Expr * e, unsigned long long i = -1 )
+UniqueExpr::UniqueExpr( const CodeLocation & loc, const Expr * e, unsigned long long i )
 : Expr( loc, e->result ), id( i ) {
 	assert( expr );
-	if ( id == -1 ) {
-		assert( nextId != -1 );
+	if ( id == -1ull ) {
+		assert( nextId != -1ull );
 		id = nextId++;
 	}
+}
+
 }
 
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/Fwd.hpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -125,6 +125,4 @@
 class ConstructorInit;
 
-class Constant;
-
 class Label;
 
@@ -135,4 +133,7 @@
 std::string toString( const Node * );
 
+template < typename ... Params >
+std::string toString( const Params & ... params );
+
 typedef unsigned int UniqueId;
 
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/Node.cpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -16,8 +16,12 @@
 #include "Node.hpp"
 #include "Fwd.hpp"
+
+#include "Attribute.hpp"
 #include "Decl.hpp"
 #include "Expr.hpp"
+#include "Init.hpp"
 #include "Stmt.hpp"
 #include "Type.hpp"
+#include "TypeSubstitution.hpp"
 
 template< typename node_t, enum ast::Node::ref_type ref_t >
@@ -26,4 +30,17 @@
 template< typename node_t, enum ast::Node::ref_type ref_t >
 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
+
+/// Sets this pointer to a mutated version of a pointer (possibly) owned elsehere.
+/// Returns a mutable version of the pointer in this node.
+template< typename node_t, enum ast::Node::ref_type ref_t >
+node_t * ast::ptr_base<node_t, ref_t>::set_and_mutate( const node_t * n ) {
+	// ensure ownership of `n` by this node to avoid spurious single-owner mutates
+	assign( n );
+	// get mutable version of `n`
+	auto r = mutate( node );
+	// re-assign mutable version in case `mutate()` produced a new pointer
+	assign( r );
+	return r;
+}
 
 template class ast::ptr_base< ast::Node, ast::Node::ref_type::weak >;
@@ -227,6 +244,4 @@
 template class ast::ptr_base< ast::ConstructorInit, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::ConstructorInit, ast::Node::ref_type::strong >;
-template class ast::ptr_base< ast::Constant, ast::Node::ref_type::weak >;
-template class ast::ptr_base< ast::Constant, ast::Node::ref_type::strong >;
 template class ast::ptr_base< ast::Attribute, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::Attribute, ast::Node::ref_type::strong >;
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/Node.hpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -143,13 +143,5 @@
 	/// Sets this pointer to a mutated version of a pointer (possibly) owned elsehere.
 	/// Returns a mutable version of the pointer in this node.
-	node_t * set_and_mutate( const node_t * n ) {
-		// ensure ownership of `n` by this node to avoid spurious single-owner mutates
-		assign( n );
-		// get mutable version of `n`
-		auto r = mutate( node );
-		// re-assign mutable version in case `mutate()` produced a new pointer
-		assign( r );
-		return r;
-	}
+	node_t * set_and_mutate( const node_t * n );
 
 	using ptr = const node_t *;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/Pass.hpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -175,5 +175,4 @@
 	const ast::Init *             visit( const ast::ListInit             * ) override final;
 	const ast::Init *             visit( const ast::ConstructorInit      * ) override final;
-	const ast::Constant *         visit( const ast::Constant             * ) override final;
 	const ast::Attribute *        visit( const ast::Attribute            * ) override final;
 	const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/Pass.impl.hpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -791,4 +791,129 @@
 
 //--------------------------------------------------------------------------
+// CatchStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		// catch statements introduce a level of scope (for the caught exception)
+		guard_indexer guard { *this };
+		maybe_accept( node, &CatchStmt::decl );
+		maybe_accept( node, &CatchStmt::cond );
+		maybe_accept( node, &CatchStmt::body );
+	})
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// FinallyStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &FinallyStmt::body );
+	)
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// WaitForStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {
+	VISIT_START( node );
+		// for( auto & clause : node->clauses ) {
+		// 	maybeAccept_impl( clause.target.function, *this );
+		// 	maybeAccept_impl( clause.target.arguments, *this );
+
+		// 	maybeAccept_impl( clause.statement, *this );
+		// 	maybeAccept_impl( clause.condition, *this );
+		// }
+
+	#define maybe_accept(field) \
+		if(node->field) { \
+			auto nval = call_accept( node->field ); \
+			if(nval != node->field ) { \
+				auto nparent = mutate(node); \
+				nparent->field = nval; \
+				node = nparent; \
+			} \
+		}
+
+	VISIT(
+		maybe_accept( timeout.time );
+		maybe_accept( timeout.stmt );
+		maybe_accept( timeout.cond );
+		maybe_accept( orElse.stmt  );
+		maybe_accept( orElse.cond  );
+	)
+
+	#undef maybe_accept
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// WithStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &WithStmt::exprs );
+		{
+			// catch statements introduce a level of scope (for the caught exception)
+			guard_indexer guard { *this };
+			__pass::indexer::addWith( pass, 0, node->exprs, node );
+			maybe_accept( node, &WithStmt::stmt );
+		}
+	)
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// NullStmt
+template< typename pass_t >
+const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {
+	VISIT_START( node );
+	VISIT_END( NullStmt, node );
+}
+
+//--------------------------------------------------------------------------
+// DeclStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &DeclStmt::decl );
+	)
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// ImplicitCtorDtorStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
+	VISIT_START( node );
+
+	// For now this isn't visited, it is unclear if this causes problem
+	// if all tests are known to pass, remove this code
+	// VISIT(
+	// 	maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
+	// )
+
+	VISIT_END( Stmt, node );
+}
+
+
+
+
+
+
+//--------------------------------------------------------------------------
 // SingleInit
 template< typename pass_t >
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/Pass.proto.hpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -241,5 +241,6 @@
 		INDEXER_FUNC1( addUnion  , const UnionDecl *     );
 		INDEXER_FUNC1( addTrait  , const TraitDecl *     );
-		INDEXER_FUNC2( addWith   , const std::list< ptr<Expr> > &, const Node * );
+		INDEXER_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Node * );
+		INDEXER_FUNC2( addWith   , const std::list  < ptr<Expr> > &, const Node * );
 
 		// A few extra functions have more complicated behaviour, they are hand written
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision 246c245850d55831cc2fd8e987ae1d76506c6fdd)
+++ src/AST/Visitor.hpp	(revision 10a122529b10d75c4935203b1402bf9e714a91e7)
@@ -111,5 +111,4 @@
     virtual const ast::Init *             visit( const ast::ListInit             * ) = 0;
     virtual const ast::Init *             visit( const ast::ConstructorInit      * ) = 0;
-    virtual const ast::Constant *         visit( const ast::Constant             * ) = 0;
     virtual const ast::Attribute *        visit( const ast::Attribute            * ) = 0;
     virtual const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) = 0;
