Index: src/Common/PassVisitor.h
===================================================================
--- src/Common/PassVisitor.h	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/Common/PassVisitor.h	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -4,4 +4,5 @@
 
 #include <stack>
+#include <type_traits>
 
 #include "Common/Stats.h"
@@ -301,5 +302,5 @@
 
 
-	TypeSubstitution ** 		get_env_ptr    () { return env_impl             ( pass, 0); }
+	auto			 		get_env_ptr    () -> decltype(env_impl( pass, 0)) { return env_impl( pass, 0); }
 	std::list< Statement* > * 	get_beforeStmts() { return stmtsToAddBefore_impl( pass, 0); }
 	std::list< Statement* > * 	get_afterStmts () { return stmtsToAddAfter_impl ( pass, 0); }
@@ -348,4 +349,13 @@
 };
 
+class WithConstTypeSubstitution {
+protected:
+	WithConstTypeSubstitution() = default;
+	~WithConstTypeSubstitution() = default;
+
+public:
+	const TypeSubstitution * env = nullptr;
+};
+
 class WithStmtsToAdd {
 protected:
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/Common/PassVisitor.impl.h	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -253,5 +253,5 @@
 
 	// don't want statements from outer CompoundStmts to be added to this CompoundStmt
-	ValueGuardPtr< TypeSubstitution * >  oldEnv        ( get_env_ptr    () );
+	ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type >  oldEnv( get_env_ptr() );
 	ValueGuardPtr< DeclList_t >          oldBeforeDecls( get_beforeDecls() );
 	ValueGuardPtr< DeclList_t >          oldAfterDecls ( get_afterDecls () );
@@ -1995,5 +1995,5 @@
 
 	// don't want statements from outer CompoundStmts to be added to this StmtExpr
-	ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
+	ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type >  oldEnv( get_env_ptr() );
 	ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
 	ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );
@@ -2012,5 +2012,5 @@
 
 	// don't want statements from outer CompoundStmts to be added to this StmtExpr
-	ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
+	ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type >  oldEnv( get_env_ptr() );
 	ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
 	ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );
Index: src/Common/PassVisitor.proto.h
===================================================================
--- src/Common/PassVisitor.proto.h	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/Common/PassVisitor.proto.h	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -165,5 +165,5 @@
 static inline type * name##_impl( __attribute__((unused)) pass_type& pass, __attribute__((unused)) long unused ) { return nullptr;}    \
 
-FIELD_PTR( TypeSubstitution *, env )
+FIELD_PTR( const TypeSubstitution *, env )
 FIELD_PTR( std::list< Statement* >, stmtsToAddBefore )
 FIELD_PTR( std::list< Statement* >, stmtsToAddAfter  )
Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/GenPoly/Box.cc	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -76,5 +76,5 @@
 
 		/// Replaces polymorphic return types with out-parameters, replaces calls to polymorphic functions with adapter calls as needed, and adds appropriate type variables to the function call
-		class Pass1 final : public BoxPass, public WithTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting {
+		class Pass1 final : public BoxPass, public WithConstTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting {
 		  public:
 			Pass1();
@@ -150,5 +150,5 @@
 		/// * Calculates polymorphic offsetof expressions from offset array
 		/// * Inserts dynamic calculation of polymorphic type layouts where needed
-		class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithTypeSubstitution {
+		class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithConstTypeSubstitution {
 		public:
 			PolyGenericCalculator();
@@ -1764,7 +1764,7 @@
 
 		Expression *PolyGenericCalculator::postmutate( SizeofExpr *sizeofExpr ) {
-			Type *ty = sizeofExpr->get_isType() ? 
+			Type *ty = sizeofExpr->get_isType() ?
 				sizeofExpr->get_type() : sizeofExpr->get_expr()->get_result();
-			
+
 			Expression * gen = genSizeof( ty );
 			if ( gen ) {
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/GenPoly/GenPoly.cc	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -440,5 +440,5 @@
 	}
 
-	bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, TypeSubstitution * env ) {
+	bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
 		// is parameter is not polymorphic, don't need to box
 		if ( ! isPolyType( param, exprTyVars ) ) return false;
@@ -450,5 +450,5 @@
 	}
 
-	bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, TypeSubstitution * env ) {
+	bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
 		FunctionType * function = getFunctionType( appExpr->function->result );
 		assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() );
Index: src/GenPoly/GenPoly.h
===================================================================
--- src/GenPoly/GenPoly.h	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/GenPoly/GenPoly.h	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -81,8 +81,8 @@
 
 	/// true if arg requires boxing given exprTyVars
-	bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, TypeSubstitution * env );
+	bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );
 
 	/// true if arg requires boxing in the call to appExpr
-	bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, TypeSubstitution * env );
+	bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );
 
 	/// Adds the type variable `tyVar` to `tyVarMap`
Index: src/GenPoly/InstantiateGeneric.cc
===================================================================
--- src/GenPoly/InstantiateGeneric.cc	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/GenPoly/InstantiateGeneric.cc	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -168,5 +168,5 @@
 
 	/// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately
-	struct GenericInstantiator final : public WithTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards {
+	struct GenericInstantiator final : public WithConstTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards {
 		/// Map of (generic type, parameter list) pairs to concrete type instantiations
 		InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
Index: src/GenPoly/Specialize.cc
===================================================================
--- src/GenPoly/Specialize.cc	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/GenPoly/Specialize.cc	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -42,5 +42,5 @@
 
 namespace GenPoly {
-	struct Specialize final : public WithTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {
+	struct Specialize final : public WithConstTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {
 		Expression * postmutate( ApplicationExpr *applicationExpr );
 		Expression * postmutate( CastExpr *castExpr );
@@ -54,5 +54,5 @@
 
 	/// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type.
-	bool needsPolySpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
+	bool needsPolySpecialization( Type *formalType, Type *actualType, const TypeSubstitution *env ) {
 		if ( env ) {
 			using namespace ResolvExpr;
@@ -145,5 +145,5 @@
 	}
 
-	bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
+	bool needsSpecialization( Type *formalType, Type *actualType, const TypeSubstitution *env ) {
 		return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType );
 	}
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/InitTweak/FixInit.cc	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -72,5 +72,5 @@
 		};
 
-		struct InsertImplicitCalls : public WithTypeSubstitution {
+		struct InsertImplicitCalls : public WithConstTypeSubstitution {
 			/// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
 			/// function calls need their parameters to be copy constructed
@@ -187,5 +187,5 @@
 		};
 
-		class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors>, public WithTypeSubstitution {
+		class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors>, public WithConstTypeSubstitution {
 		  public:
 			FixCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ){}
Index: src/SynTree/TypeSubstitution.cc
===================================================================
--- src/SynTree/TypeSubstitution.cc	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/SynTree/TypeSubstitution.cc	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -108,6 +108,7 @@
 namespace {
 	struct EnvTrimmer {
-		TypeSubstitution * env, * newEnv;
-		EnvTrimmer( TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
+		const TypeSubstitution * env;
+		TypeSubstitution * newEnv;
+		EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
 		void previsit( TypeDecl * tyDecl ) {
 			// transfer known bindings for seen type variables
@@ -120,5 +121,5 @@
 
 /// reduce environment to just the parts that are referenced in a given expression
-TypeSubstitution * TypeSubstitution::newFromExpr( Expression * expr, TypeSubstitution * env ) {
+TypeSubstitution * TypeSubstitution::newFromExpr( Expression * expr, const TypeSubstitution * env ) {
 	if ( env ) {
 		TypeSubstitution * newEnv = new TypeSubstitution();
Index: src/SynTree/TypeSubstitution.h
===================================================================
--- src/SynTree/TypeSubstitution.h	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/SynTree/TypeSubstitution.h	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -39,6 +39,6 @@
 	TypeSubstitution &operator=( const TypeSubstitution &other );
 
-	template< typename SynTreeClass > int apply( SynTreeClass *&input );
-	template< typename SynTreeClass > int applyFree( SynTreeClass *&input );
+	template< typename SynTreeClass > int apply( SynTreeClass *&input ) const;
+	template< typename SynTreeClass > int applyFree( SynTreeClass *&input ) const;
 
 	void add( std::string formalType, Type *actualType );
@@ -56,5 +56,5 @@
 
 	/// create a new TypeSubstitution using bindings from env containing all of the type variables in expr
-	static TypeSubstitution * newFromExpr( Expression * expr, TypeSubstitution * env );
+	static TypeSubstitution * newFromExpr( Expression * expr, const TypeSubstitution * env );
 
 	void normalize();
@@ -130,5 +130,5 @@
 // definitition must happen after PassVisitor is included so that WithGuards can be used
 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
-		Substituter( TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
+		Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
 
 		Type * postmutate( TypeInstType * aggregateUseType );
@@ -143,5 +143,5 @@
 		void premutate( UnionInstType * aggregateUseType );
 
-		TypeSubstitution & sub;
+		const TypeSubstitution & sub;
 		int subCount = 0;
 		bool freeOnly;
@@ -151,5 +151,5 @@
 
 template< typename SynTreeClass >
-int TypeSubstitution::apply( SynTreeClass *&input ) {
+int TypeSubstitution::apply( SynTreeClass *&input ) const {
 	assert( input );
 	PassVisitor<Substituter> sub( *this, false );
@@ -163,5 +163,5 @@
 
 template< typename SynTreeClass >
-int TypeSubstitution::applyFree( SynTreeClass *&input ) {
+int TypeSubstitution::applyFree( SynTreeClass *&input ) const {
 	assert( input );
 	PassVisitor<Substituter> sub( *this, true );
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 0c0f548dfcc801e54284c7b6f68f8dd6d9b68c3c)
+++ src/Tuples/TupleExpansion.cc	(revision 02fdb8eb4c22b14a7fc7116a96f53d73dae71205)
@@ -58,5 +58,5 @@
 		};
 
-		struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithTypeSubstitution {
+		struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {
 			Type * postmutate( TupleType * tupleType );
 
