Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision cb914379c23218fde6d6aaf354fb109d6e02f15c)
+++ src/GenPoly/Box.cc	(revision 22854f8631ff59092624dcefc8874b238a0e4329)
@@ -1298,5 +1298,5 @@
 			FunctionType * ftype = functionDecl->get_functionType();
 			if ( ! ftype->get_returnVals().empty() && functionDecl->get_statements() ) {
-				if ( functionDecl->get_name() != "?=?" && ! isPrefix( functionDecl->get_name(), "_thunk" ) ) { // xxx - remove check for ?=? once reference types are in; remove check for prefix once thunks properly use ctor/dtors
+				if ( functionDecl->get_name() != "?=?" && ! isPrefix( functionDecl->get_name(), "_thunk" ) && ! isPrefix( functionDecl->get_name(), "_adapter" ) ) { // xxx - remove check for ?=? once reference types are in; remove check for prefix once thunks properly use ctor/dtors
 					assert( ftype->get_returnVals().size() == 1 );
 					DeclarationWithType * retval = ftype->get_returnVals().front();
Index: src/GenPoly/Specialize.cc
===================================================================
--- src/GenPoly/Specialize.cc	(revision cb914379c23218fde6d6aaf354fb109d6e02f15c)
+++ src/GenPoly/Specialize.cc	(revision 22854f8631ff59092624dcefc8874b238a0e4329)
@@ -168,4 +168,26 @@
 	}
 
+	struct EnvTrimmer : public Visitor {
+		TypeSubstitution * env, * newEnv;
+		EnvTrimmer( TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
+		virtual void visit( TypeDecl * tyDecl ) {
+			// transfer known bindings for seen type variables
+			if ( Type * t = env->lookup( tyDecl->get_name() ) ) {
+				newEnv->add( tyDecl->get_name(), t );
+			}
+		}
+	};
+
+	/// reduce environment to just the parts that are referenced in a given expression
+	TypeSubstitution * trimEnv( ApplicationExpr * expr, TypeSubstitution * env ) {
+		if ( env ) {
+			TypeSubstitution * newEnv = new TypeSubstitution();
+			EnvTrimmer trimmer( env, newEnv );
+			expr->accept( trimmer );
+			return newEnv;
+		}
+		return nullptr;
+	}
+
 	/// Generates a thunk that calls `actual` with type `funType` and returns its address
 	Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
@@ -211,5 +233,5 @@
 		}
 
-		appExpr->set_env( maybeClone( env ) );
+		appExpr->set_env( trimEnv( appExpr, env ) );
 		if ( inferParams ) {
 			appExpr->get_inferParams() = *inferParams;
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision cb914379c23218fde6d6aaf354fb109d6e02f15c)
+++ src/InitTweak/FixInit.cc	(revision 22854f8631ff59092624dcefc8874b238a0e4329)
@@ -52,4 +52,5 @@
 	namespace {
 		typedef std::unordered_map< Expression *, TypeSubstitution * > EnvMap;
+		typedef std::unordered_map< int, int > UnqCount;
 
 		class InsertImplicitCalls final : public GenPoly::PolyMutator {
@@ -74,10 +75,10 @@
 			/// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
 			/// arguments and return value temporaries
-			static void resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap );
+			static void resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap, UnqCount & unqCount );
 
 			typedef SymTab::Indexer Parent;
 			using Parent::visit;
 
-			ResolveCopyCtors( const EnvMap & envMap ) : envMap( envMap ) {}
+			ResolveCopyCtors( const EnvMap & envMap, UnqCount & unqCount ) : envMap( envMap ), unqCount( unqCount ) {}
 
 			virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ) override;
@@ -94,4 +95,5 @@
 			TypeSubstitution * env;
 			const EnvMap & envMap;
+			UnqCount & unqCount; // count the number of times each unique expr ID appears
 		};
 
@@ -202,7 +204,8 @@
 		class FixCopyCtors final : public GenPoly::PolyMutator {
 		  public:
+			FixCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ){}
 			/// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, call expression,
 			/// and destructors
-			static void fixCopyCtors( std::list< Declaration * > &translationUnit );
+			static void fixCopyCtors( std::list< Declaration * > &translationUnit, UnqCount & unqCount );
 
 			typedef GenPoly::PolyMutator Parent;
@@ -211,4 +214,6 @@
 			virtual Expression * mutate( UniqueExpr * unqExpr ) override;
 			virtual Expression * mutate( StmtExpr * stmtExpr ) override;
+
+			UnqCount & unqCount;
 		};
 
@@ -272,12 +277,13 @@
 
 		EnvMap envMap;
+		UnqCount unqCount;
 
 		InsertImplicitCalls::insert( translationUnit, envMap );
-		ResolveCopyCtors::resolveImplicitCalls( translationUnit, envMap );
+		ResolveCopyCtors::resolveImplicitCalls( translationUnit, envMap, unqCount );
 		InsertDtors::insert( translationUnit );
 		FixInit::fixInitializers( translationUnit );
 
 		// FixCopyCtors must happen after FixInit, so that destructors are placed correctly
-		FixCopyCtors::fixCopyCtors( translationUnit );
+		FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
 
 		GenStructMemberCalls::generate( translationUnit );
@@ -298,6 +304,6 @@
 		}
 
-		void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap ) {
-			ResolveCopyCtors resolver( envMap );
+		void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap, UnqCount & unqCount ) {
+			ResolveCopyCtors resolver( envMap, unqCount );
 			acceptAll( translationUnit, resolver );
 		}
@@ -329,6 +335,6 @@
 		}
 
-		void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit ) {
-			FixCopyCtors fixer;
+		void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
+			FixCopyCtors fixer( unqCount );
 			mutateAll( translationUnit, fixer );
 		}
@@ -520,4 +526,5 @@
 		void ResolveCopyCtors::visit( UniqueExpr * unqExpr ) {
 			static std::unordered_set< int > vars;
+			unqCount[ unqExpr->get_id() ]++;  // count the number of unique expressions for each ID
 			if ( vars.count( unqExpr->get_id() ) ) {
 				// xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
@@ -636,4 +643,6 @@
 
 		Expression * FixCopyCtors::mutate( UniqueExpr * unqExpr ) {
+			unqCount[ unqExpr->get_id() ]--;
+			static std::unordered_map< int, std::list< Statement * > > dtors;
 			static std::unordered_map< int, UniqueExpr * > unqMap;
 			static std::unordered_set< int > addDeref;
@@ -645,4 +654,7 @@
 				delete unqExpr->get_result();
 				unqExpr->set_result( maybeClone( unqExpr->get_expr()->get_result() ) );
+				if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
+					stmtsToAdd.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
+				}
 				if ( addDeref.count( unqExpr->get_id() ) ) {
 					// other UniqueExpr was dereferenced because it was an lvalue return, so this one should be too
@@ -651,5 +663,7 @@
 				return unqExpr;
 			}
-			unqExpr = safe_dynamic_cast< UniqueExpr * >( Parent::mutate( unqExpr ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
+			FixCopyCtors fixer( unqCount );
+			unqExpr->set_expr( unqExpr->get_expr()->acceptMutator( fixer ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
+			stmtsToAdd.splice( stmtsToAdd.end(), fixer.stmtsToAdd );
 			unqMap[unqExpr->get_id()] = unqExpr;
 			if ( UntypedExpr * deref = dynamic_cast< UntypedExpr * >( unqExpr->get_expr() ) ) {
@@ -661,4 +675,9 @@
 				getCallArg( deref, 0 ) = unqExpr;
 				addDeref.insert( unqExpr->get_id() );
+				if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
+					stmtsToAdd.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
+				} else { // remember dtors for last instance of unique expr
+					dtors[ unqExpr->get_id() ] = fixer.stmtsToAddAfter;
+				}
 				return deref;
 			}
Index: src/libcfa/iostream.c
===================================================================
--- src/libcfa/iostream.c	(revision cb914379c23218fde6d6aaf354fb109d6e02f15c)
+++ src/libcfa/iostream.c	(revision 22854f8631ff59092624dcefc8874b238a0e4329)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Mar 22 17:21:23 2017
-// Update Count     : 358
+// Last Modified On : Wed Mar 22 17:46:06 2017
+// Update Count     : 359
 //
 
@@ -201,5 +201,5 @@
 forall( dtype ostype, otype T, ttype Params | ostream( ostype ) | writeable( T ) | { ostype * ?|?( ostype *, Params ); } )
 ostype * ?|?( ostype * os, T arg, Params rest ) {
-	forall( ttype Params ) ostype * prtTuple( ostype * os, T arg, Params rest ) {
+	forall( ttype Params ) ostype * prtTuple( T arg, Params rest ) {
 		os | arg;										// print first argument
 		os | rest;										// print remaining arguments
@@ -207,5 +207,5 @@
 	} // prtTuple
 	sepSetCur( os, sepGetTuple( os ) );					// switch to tuple separator
-	prtTuple( os, arg, rest );							// recursively print tuple
+	prtTuple( arg, rest );								// recursively print tuple
 	sepSetCur( os, sepGet( os ) );						// switch to regular separator
 	return os;
