Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/GenPoly/Box.cc	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -783,5 +783,5 @@
 		void Pass1::boxParams( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) {
 			for ( std::list< DeclarationWithType *>::const_iterator param = function->get_parameters().begin(); param != function->get_parameters().end(); ++param, ++arg ) {
-				assert( arg != appExpr->get_args().end() );
+				assertf( arg != appExpr->get_args().end(), "boxParams: missing argument for param %s to %s in %s", toString( *param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() );
 				addCast( *arg, (*param)->get_type(), exprTyVars );
 				boxParam( (*param)->get_type(), *arg, exprTyVars );
Index: src/GenPoly/Specialize.cc
===================================================================
--- src/GenPoly/Specialize.cc	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/GenPoly/Specialize.cc	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -112,8 +112,7 @@
 		FunctionType *newType = funType->clone();
 		if ( env ) {
-			TypeSubstitution newEnv( *env );
 			// it is important to replace only occurrences of type variables that occur free in the
 			// thunk's type
-			newEnv.applyFree( newType );
+			env->applyFree( newType );
 		} // if
 		// create new thunk with same signature as formal type (C linkage, empty body)
@@ -167,6 +166,5 @@
 		assertf( actual->has_result(), "attempting to specialize an untyped expression" );
 		if ( needsSpecialization( formalType, actual->get_result(), env ) ) {
-			FunctionType *funType;
-			if ( ( funType = getFunctionType( formalType ) ) ) {
+			if ( FunctionType *funType = getFunctionType( formalType ) ) {
 				ApplicationExpr *appExpr;
 				VariableExpr *varExpr;
@@ -188,5 +186,4 @@
 
 	bool TupleSpecializer::needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
-		// std::cerr << "asking if type needs tuple spec: " << formalType << std::endl;
 		if ( FunctionType * ftype = getFunctionType( formalType ) ) {
 			return ftype->isTtype();
@@ -215,5 +212,5 @@
 	void fixLastArg( Expression * last, Iterator begin, Iterator end, OutIterator out ) {
 		// safe_dynamic_cast for the assertion
-		safe_dynamic_cast< TupleType * >( last->get_result() ); // xxx - it's quite possible this will trigger for the unary case...
+		safe_dynamic_cast< TupleType * >( last->get_result() );
 		unsigned idx = 0;
 		for ( ; begin != end; ++begin ) {
@@ -227,12 +224,10 @@
 	Expression * TupleSpecializer::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
 		static UniqueName thunkNamer( "_tupleThunk" );
-		// std::cerr << "creating tuple thunk for " << funType << std::endl;
 
 		FunctionType *newType = funType->clone();
 		if ( env ) {
-			TypeSubstitution newEnv( *env );
 			// it is important to replace only occurrences of type variables that occur free in the
 			// thunk's type
-			newEnv.applyFree( newType );
+			env->applyFree( newType );
 		} // if
 		// create new thunk with same signature as formal type (C linkage, empty body)
@@ -246,7 +241,11 @@
 		UniqueName paramNamer( paramPrefix );
 		ApplicationExpr *appExpr = new ApplicationExpr( actual );
-		// std::cerr << actual << std::endl;
-
-		FunctionType * actualType = getFunctionType( actual->get_result() );
+
+		FunctionType * actualType = getFunctionType( actual->get_result() )->clone();
+		if ( env ) {
+			// need to apply the environment to the actual function's type, since it may itself be polymorphic
+			env->apply( actualType );
+		}
+		std::unique_ptr< FunctionType > actualTypeManager( actualType ); // for RAII
 		std::list< DeclarationWithType * >::iterator actualBegin = actualType->get_parameters().begin();
 		std::list< DeclarationWithType * >::iterator actualEnd = actualType->get_parameters().end();
@@ -282,5 +281,5 @@
 		std::list< Statement* > oldStmts;
 		oldStmts.splice( oldStmts.end(), stmtsToAdd );
-		spec.handleExplicitParams( appExpr );
+		spec.mutate( appExpr );
 		paramPrefix = oldParamPrefix;
 		// write any statements added for recursive specializations into the thunk body
@@ -297,6 +296,4 @@
 		} // if
 		thunkFunc->get_statements()->get_kids().push_back( appStmt );
-
-		// std::cerr << "thunkFunc is: " << thunkFunc << std::endl;
 
 		// add thunk definition to queue of statements to add
@@ -326,5 +323,5 @@
 			// don't need to do this for intrinsic calls, because they aren't actually passed
 			for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) {
-				inferParam->second.expr = specializer->doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );
+				inferParam->second.expr = specializer->doSpecialization( inferParam->second.formalType, inferParam->second.expr, inferParam->second.inferParams.get() );
 			}
 			handleExplicitParams( appExpr );
Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/ResolvExpr/AdjustExprType.cc	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -22,4 +22,5 @@
 	class AdjustExprType : public Mutator {
 		typedef Mutator Parent;
+		using Parent::mutate;
 	  public:
 		AdjustExprType( const TypeEnvironment &env, const SymTab::Indexer &indexer );
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -339,5 +339,5 @@
 			unifiableVars[ (*tyvar)->get_name() ] = TypeDecl::Data{ *tyvar };
 			for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
-				needAssertions[ *assert ] = true;
+				needAssertions[ *assert ].isUsed = true;
 			}
 ///     needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
@@ -380,5 +380,4 @@
 			}
 			*out++ = arg;
-			return true;
 		} else if ( actualIt != actualEnd ) {
 			// both actualType and formalType are atomic (non-tuple) types - if they unify
@@ -467,5 +466,5 @@
 	void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
 		for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
-			if ( i->second == true ) {
+			if ( i->second.isUsed ) {
 				i->first->accept( indexer );
 			}
@@ -478,4 +477,9 @@
 		if ( begin == end ) {
 			if ( newNeed.empty() ) {
+				PRINT(
+					std::cerr << "all assertions satisfied, output alternative: ";
+					newAlt.print( std::cerr );
+					std::cerr << std::endl;
+				);
 				*out++ = newAlt;
 				return;
@@ -494,5 +498,5 @@
 
 		ForwardIterator cur = begin++;
-		if ( ! cur->second ) {
+		if ( ! cur->second.isUsed ) {
 			inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out );
 			return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
@@ -538,4 +542,14 @@
 				assert( (*candidate)->get_uniqueId() );
 				DeclarationWithType *candDecl = static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) );
+
+				// everything with an empty idChain was pulled in by the current assertion.
+				// add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
+				for ( auto & a : newerNeed ) {
+					if ( a.second.idChain.empty() ) {
+						a.second.idChain = cur->second.idChain;
+						a.second.idChain.push_back( curDecl->get_uniqueId() );
+					}
+				}
+
 				//AssertionParentSet newNeedParents( needParents );
 				// skip repeatingly-self-recursive assertion satisfaction
@@ -553,6 +567,11 @@
 				)
 				ApplicationExpr *appExpr = static_cast< ApplicationExpr* >( newerAlt.expr );
+				// follow the current assertion's ID chain to find the correct set of inferred parameters to add the candidate to (i.e. the set of inferred parameters belonging to the entity which requested the assertion parameter).
+				InferredParams * inferParameters = &appExpr->get_inferParams();
+				for ( UniqueId id : cur->second.idChain ) {
+					inferParameters = (*inferParameters)[ id ].inferParams.get();
+				}
 				// XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
-				appExpr->get_inferParams()[ curDecl->get_uniqueId() ] = ParamEntry( (*candidate)->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
+				(*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( (*candidate)->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
 				inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out );
 			} else {
Index: src/ResolvExpr/FindOpenVars.cc
===================================================================
--- src/ResolvExpr/FindOpenVars.cc	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/ResolvExpr/FindOpenVars.cc	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -50,5 +50,5 @@
 				openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
 				for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
-					needAssertions[ *assert ] = false;
+					needAssertions[ *assert ].isUsed = false;
 				}
 ///       cloneAll( (*i)->get_assertions(), needAssertions );
@@ -59,5 +59,5 @@
 				closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
 				for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
-					haveAssertions[ *assert ] = false;
+					haveAssertions[ *assert ].isUsed = false;
 				}
 ///       cloneAll( (*i)->get_assertions(), haveAssertions );
Index: src/ResolvExpr/TypeEnvironment.cc
===================================================================
--- src/ResolvExpr/TypeEnvironment.cc	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/ResolvExpr/TypeEnvironment.cc	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -75,5 +75,5 @@
 		for ( AssertionSet::const_iterator i = assertions.begin(); i != assertions.end(); ++i ) {
 			i->first->print( os, indent );
-			if ( i->second ) {
+			if ( i->second.isUsed ) {
 				os << "(used)";
 			} else {
Index: src/ResolvExpr/TypeEnvironment.h
===================================================================
--- src/ResolvExpr/TypeEnvironment.h	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/ResolvExpr/TypeEnvironment.h	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -31,5 +31,12 @@
 		bool operator()( DeclarationWithType * d1, DeclarationWithType * d2 ) const;
 	};
-	typedef std::map< DeclarationWithType*, bool, AssertCompare > AssertionSet;
+	struct AssertionSetValue {
+		bool isUsed;
+		// chain of Unique IDs of the assertion declarations. The first ID in the chain is the ID of an assertion on the current type,
+		// with each successive ID being the ID of an assertion pulled in by the previous ID. The last ID in the chain is
+		// the ID of the assertion that pulled in the current assertion.
+		std::list< UniqueId > idChain;
+	};
+	typedef std::map< DeclarationWithType*, AssertionSetValue, AssertCompare > AssertionSet;
 	typedef std::map< std::string, TypeDecl::Data > OpenVarSet;
 
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/ResolvExpr/Unify.cc	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -157,10 +157,11 @@
 			// if the type variable is specified to be a complete type then the incoming
 			// type must also be complete
+			// xxx - should this also check that type is not a tuple type and that it's not a ttype?
 			return ! isFtype( type, indexer ) && (! data.isComplete || isComplete( type ));
 		  case TypeDecl::Ftype:
 			return isFtype( type, indexer );
 			case TypeDecl::Ttype:
-			// ttype eats up any remaining parameters, no matter the type
-			return true;
+			// ttype unifies with any tuple type
+			return dynamic_cast< TupleType * >( type );
 		} // switch
 		return false;
@@ -433,5 +434,5 @@
 		if ( i != assertions.end() ) {
 ///     std::cerr << "found it!" << std::endl;
-			i->second = true;
+			i->second.isUsed = true;
 		} // if
 	}
@@ -488,5 +489,5 @@
 
 	template< typename Iterator >
-	Type * combineTypes( Iterator begin, Iterator end ) {
+	std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end ) {
 		std::list< Type * > types;
 		for ( ; begin != end; ++begin ) {
@@ -494,5 +495,5 @@
 			flatten( (*begin)->get_type(), back_inserter( types ) );
 		}
-		return new TupleType( Type::Qualifiers(), types );
+		return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );
 	}
 
@@ -504,25 +505,22 @@
 			bool isTtype1 = Tuples::isTtype( t1 );
 			bool isTtype2 = Tuples::isTtype( t2 );
-			// xxx - assumes ttype must be last parameter; needs cleanup; use unique_ptr for combinedType
+			// xxx - assumes ttype must be last parameter
+			// xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
 			if ( isTtype1 && ! isTtype2 ) {
 				// combine all of the things in list2, then unify
-				Type * combinedType = combineTypes( list2Begin, list2End );
-				return unifyExact( t1, combinedType, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
+				return unifyExact( t1, combineTypes( list2Begin, list2End ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
 			} else if ( isTtype2 && ! isTtype1 ) {
 				// combine all of the things in list1, then unify
-				Type * combinedType = combineTypes( list1Begin, list1End );
-				return unifyExact( combinedType, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
+				return unifyExact( combineTypes( list1Begin, list1End ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
 			} else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
 				return false;
 			} // if
 		} // for
-		// if ( list1Begin != list1End || list2Begin != list2End ) {
-		// 	return false;
+		// may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype
 		if ( list1Begin != list1End ) {
 			// try unifying empty tuple type with ttype
 			Type * t1 = (*list1Begin)->get_type();
 			if ( Tuples::isTtype( t1 ) ) {
-				Type * combinedType = combineTypes( list2Begin, list2End );
-				return unifyExact( t1, combinedType, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
+				return unifyExact( t1, combineTypes( list2Begin, list2End ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
 			} else return false;
 		} else if ( list2Begin != list2End ) {
@@ -530,6 +528,5 @@
 			Type * t2 = (*list2Begin)->get_type();
 			if ( Tuples::isTtype( t2 ) ) {
-				Type * combinedType = combineTypes( list1Begin, list1End );
-				return unifyExact( combinedType, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
+				return unifyExact( combineTypes( list1Begin, list1End ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
 			} else return false;
 		} else {
@@ -538,12 +535,58 @@
 	}
 
+	/// Finds ttypes and replaces them with their expansion, if known.
+	/// This needs to be done so that satisfying ttype assertions is easier.
+	/// If this isn't done then argument lists can have wildly different
+	/// size and structure, when they should be compatible.
+	struct TtypeExpander : public Mutator {
+		TypeEnvironment & env;
+		TtypeExpander( TypeEnvironment & env ) : env( env ) {}
+		Type * mutate( TypeInstType * typeInst ) {
+			EqvClass eqvClass;
+			if ( env.lookup( typeInst->get_name(), eqvClass ) ) {
+				if ( eqvClass.data.kind == TypeDecl::Ttype ) {
+					// expand ttype parameter into its actual type
+					if ( eqvClass.type ) {
+						delete typeInst;
+						return eqvClass.type->clone();
+					}
+				}
+			}
+			return typeInst;
+		}
+	};
+
+	/// flattens a list of declarations, so that each tuple type has a single declaration.
+	/// makes use of TtypeExpander to ensure ttypes are flat as well.
+	void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {
+		dst.clear();
+		for ( DeclarationWithType * dcl : src ) {
+			TtypeExpander expander( env );
+			dcl->acceptMutator( expander );
+			std::list< Type * > types;
+			flatten( dcl->get_type(), back_inserter( types ) );
+			for ( Type * t : types ) {
+				dst.push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, t, nullptr ) );
+			}
+			delete dcl;
+		}
+	}
+
 	void Unify::visit(FunctionType *functionType) {
 		FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
 		if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
+			// flatten the parameter lists for both functions so that tuple structure
+			// doesn't affect unification. Must be a clone so that the types don't change.
+			std::unique_ptr<FunctionType> flatFunc( functionType->clone() );
+			std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );
+			flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );
+			flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );
+
 			// sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors
-			if ( (functionType->get_parameters().size() == otherFunction->get_parameters().size() && functionType->get_returnVals().size() == otherFunction->get_returnVals().size()) || functionType->isTtype() || otherFunction->isTtype() ) {
-				if ( unifyDeclList( functionType->get_parameters().begin(), functionType->get_parameters().end(), otherFunction->get_parameters().begin(), otherFunction->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
-					if ( unifyDeclList( functionType->get_returnVals().begin(), functionType->get_returnVals().end(), otherFunction->get_returnVals().begin(), otherFunction->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
-
+			if ( (flatFunc->get_parameters().size() == flatOther->get_parameters().size() && flatFunc->get_returnVals().size() == flatOther->get_returnVals().size()) || flatFunc->isTtype() || flatOther->isTtype() ) {
+				if ( unifyDeclList( flatFunc->get_parameters().begin(), flatFunc->get_parameters().end(), flatOther->get_parameters().begin(), flatOther->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
+					if ( unifyDeclList( flatFunc->get_returnVals().begin(), flatFunc->get_returnVals().end(), flatOther->get_returnVals().begin(), flatOther->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
+
+						// the original types must be used in mark assertions, since pointer comparisons are used
 						markAssertions( haveAssertions, needAssertions, functionType );
 						markAssertions( haveAssertions, needAssertions, otherFunction );
Index: src/ResolvExpr/typeops.h
===================================================================
--- src/ResolvExpr/typeops.h	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/ResolvExpr/typeops.h	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -164,5 +164,5 @@
 			}
 		} else {
-			*out++ = type;
+			*out++ = type->clone();
 		}
 	}
Index: src/SynTree/ApplicationExpr.cc
===================================================================
--- src/SynTree/ApplicationExpr.cc	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/SynTree/ApplicationExpr.cc	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -24,5 +24,5 @@
 
 ParamEntry::ParamEntry( const ParamEntry &other ) :
-		decl( other.decl ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
+		decl( other.decl ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ), inferParams( new InferredParams( *other.inferParams ) ) {
 }
 
@@ -34,4 +34,5 @@
 	formalType = maybeClone( other.formalType );
 	expr = maybeClone( other.expr );
+	*inferParams = *other.inferParams;
 	return *this;
 }
@@ -62,4 +63,16 @@
 }
 
+void printInferParams( const InferredParams & inferParams, std::ostream &os, int indent, int level ) {
+	if ( ! inferParams.empty() ) {
+		os << std::string(indent, ' ') << "with inferred parameters " << level << ":" << std::endl;
+		for ( InferredParams::const_iterator i = inferParams.begin(); i != inferParams.end(); ++i ) {
+			os << std::string(indent+2, ' ');
+			Declaration::declFromId( i->second.decl )->printShort( os, indent+2 );
+			os << std::endl;
+			printInferParams( *i->second.inferParams, os, indent+2, level+1 );
+		} // for
+	} // if
+}
+
 void ApplicationExpr::print( std::ostream &os, int indent ) const {
 	os << "Application of" << std::endl << std::string(indent+2, ' ');
@@ -69,12 +82,5 @@
 		printAll( args, os, indent+2 );
 	} // if
-	if ( ! inferParams.empty() ) {
-		os << std::string(indent, ' ') << "with inferred parameters:" << std::endl;
-		for ( InferredParams::const_iterator i = inferParams.begin(); i != inferParams.end(); ++i ) {
-			os << std::string(indent+2, ' ');
-			Declaration::declFromId( i->second.decl )->printShort( os, indent+2 );
-			os << std::endl;
-		} // for
-	} // if
+	printInferParams( inferParams, os, indent+2, 0 );
 	Expression::print( os, indent );
 }
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/SynTree/Expression.h	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -54,9 +54,12 @@
 };
 
+struct ParamEntry;
+typedef std::map< UniqueId, ParamEntry > InferredParams;
+
 /// ParamEntry contains the i.d. of a declaration and a type that is derived from that declaration,
 /// but subject to decay-to-pointer and type parameter renaming
 struct ParamEntry {
-	ParamEntry(): decl( 0 ), actualType( 0 ), formalType( 0 ), expr( 0 ) {}
-	ParamEntry( UniqueId decl, Type *actualType, Type *formalType, Expression* expr ): decl( decl ), actualType( actualType ), formalType( formalType ), expr( expr ) {}
+	ParamEntry(): decl( 0 ), actualType( 0 ), formalType( 0 ), expr( 0 ), inferParams( new InferredParams ) {}
+	ParamEntry( UniqueId decl, Type *actualType, Type *formalType, Expression* expr ): decl( decl ), actualType( actualType ), formalType( formalType ), expr( expr ), inferParams( new InferredParams ) {}
 	ParamEntry( const ParamEntry &other );
 	~ParamEntry();
@@ -67,7 +70,6 @@
 	Type *formalType;
 	Expression* expr;
-};
-
-typedef std::map< UniqueId, ParamEntry > InferredParams;
+	std::unique_ptr< InferredParams > inferParams;
+};
 
 /// ApplicationExpr represents the application of a function to a set of parameters.  This is the result of running an
Index: src/SynTree/TupleExpr.cc
===================================================================
--- src/SynTree/TupleExpr.cc	(revision 1e3d5b661a71dbe22595492bdc80be8525be1611)
+++ src/SynTree/TupleExpr.cc	(revision 6c3a988fe7dbaec419f8cc1c6be3085432447a99)
@@ -58,5 +58,5 @@
 TupleIndexExpr::TupleIndexExpr( Expression * tuple, unsigned int index ) : tuple( tuple ), index( index )  {
 	TupleType * type = safe_dynamic_cast< TupleType * >( tuple->get_result() );
-	assertf( type->size() > index, "TupleIndexExpr index out of bounds: tuple size %d, requested index %d", type->size(), index );
+	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() );
 	set_result( (*std::next( type->get_types().begin(), index ))->clone() );
 	get_result()->set_isLvalue( type->get_isLvalue() );
