Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/GenPoly/Box.cc	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -98,5 +98,5 @@
 			void passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes );
 			/// passes extra type parameters into a polymorphic function application
-			void passTypeVars( ApplicationExpr *appExpr, ReferenceToType *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
+			void passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
 			/// wraps a function application with a new temporary for the out-parameter return value
 			Expression *addRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *retType, std::list< Expression *>::iterator &arg );
@@ -107,5 +107,5 @@
 			Type *replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone = true );
 			/// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value
-			Expression *addDynRetParam( ApplicationExpr *appExpr, FunctionType *function, ReferenceToType *polyType, std::list< Expression *>::iterator &arg );
+			Expression *addDynRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *polyType, std::list< Expression *>::iterator &arg );
 			Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
 			void boxParam( Type *formal, Expression *&arg, const TyVarMap &exprTyVars );
@@ -769,5 +769,5 @@
 		}
 
-		void Pass1::passTypeVars( ApplicationExpr *appExpr, ReferenceToType *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) {
+		void Pass1::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) {
 			// pass size/align for type variables
 			for ( TyVarMap::const_iterator tyParm = exprTyVars.begin(); tyParm != exprTyVars.end(); ++tyParm ) {
@@ -818,14 +818,8 @@
 
 		Expression *Pass1::addRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *retType, std::list< Expression *>::iterator &arg ) {
-			// ***** Code Removal ***** After introducing a temporary variable for all return expressions, the following code appears superfluous.
-			// if ( useRetval ) {
-			// 	assert( retval );
-			// 	arg = appExpr->get_args().insert( arg, new VariableExpr( retval ) );
-			// 	arg++;
-			// } else {
-
 			// Create temporary to hold return value of polymorphic function and produce that temporary as a result
 			// using a comma expression.  Possibly change comma expression into statement expression "{}" for multiple
 			// return values.
+			assert( retType );
 			ObjectDecl *newObj = makeTemporary( retType->clone() );
 			Expression *paramExpr = new VariableExpr( newObj );
@@ -843,6 +837,4 @@
 			appExpr->set_env( 0 );
 			return commaExpr;
-			// } // if
-			// return appExpr;
 		}
 
@@ -878,5 +870,5 @@
 		}
 
-		Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, FunctionType *function, ReferenceToType *dynType, std::list< Expression *>::iterator &arg ) {
+		Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *dynType, std::list< Expression *>::iterator &arg ) {
 			assert( env );
 			Type *concrete = replaceWithConcrete( appExpr, dynType );
@@ -1288,6 +1280,6 @@
 			TyVarMap exprTyVars( (TypeDecl::Kind)-1 );
 			makeTyVarMap( function, exprTyVars );
-			ReferenceToType *concRetType = dynamic_cast< ReferenceToType* >( appExpr->get_result() ); // xxx - is concRetType a good name?
 			ReferenceToType *dynRetType = isDynRet( function, exprTyVars );
+			Type *concRetType = appExpr->get_result();// ?: dynRetType; // xxx - is concRetType a good name?
 
 			if ( dynRetType ) {
@@ -1589,8 +1581,9 @@
 			// move polymorphic return type to parameter list
 			if ( isDynRet( funcType ) ) {
-				DeclarationWithType *ret = funcType->get_returnVals().front();
+				ObjectDecl *ret = safe_dynamic_cast< ObjectDecl* >( funcType->get_returnVals().front() );
 				ret->set_type( new PointerType( Type::Qualifiers(), ret->get_type() ) );
 				funcType->get_parameters().push_front( ret );
 				funcType->get_returnVals().pop_front();
+				ret->set_init( nullptr ); // xxx - memory leak?
 			}
 
Index: src/GenPoly/PolyMutator.cc
===================================================================
--- src/GenPoly/PolyMutator.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/GenPoly/PolyMutator.cc	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -149,4 +149,20 @@
 	}
 
+	Expression *PolyMutator::mutate( StmtExpr * stmtExpr ) {
+		// don't want statements from outer CompoundStmts to be added to this StmtExpr
+		ValueGuard< std::list< Statement* > > oldStmtsToAdd( stmtsToAdd );
+		ValueGuard< std::list< Statement* > > oldStmtsToAddAfter( stmtsToAddAfter );
+
+		// xxx - not sure if these are needed, along with appropriate assignments, but I don't think so...
+		// ValueGuard< TyVarMap > oldScopeTyVars;
+		// ValueGuard< TypeSubstitution * > oldEnv;
+
+		stmtsToAdd.clear();
+		stmtsToAddAfter.clear();
+
+		stmtExpr->set_result( maybeMutate( stmtExpr->get_result(), *this ) );
+		stmtExpr->set_statements( maybeMutate( stmtExpr->get_statements(), *this ) );
+		return stmtExpr;
+	}
 
 	Initializer *PolyMutator::mutate( SingleInit *singleInit ) {
@@ -154,5 +170,4 @@
 		return singleInit;
 	}
-
 } // namespace GenPoly
 
Index: src/GenPoly/PolyMutator.h
===================================================================
--- src/GenPoly/PolyMutator.h	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/GenPoly/PolyMutator.h	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -47,4 +47,5 @@
 
 		virtual Expression* mutate(UntypedExpr *untypedExpr);
+		virtual Expression* mutate( StmtExpr *stmtExpr );
 
 		virtual Initializer* mutate(SingleInit *SingleInit);
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/InitTweak/FixInit.cc	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -904,6 +904,5 @@
 					// insert and resolve default/copy constructor call for each field that's unhandled
 					std::list< Statement * > stmt;
-					UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) );
-					deref->get_args().push_back( new VariableExpr( thisParam ) );
+					UntypedExpr * deref = UntypedExpr::createDeref( new VariableExpr( thisParam ) );
 
 					Expression * arg2 = 0;
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -218,10 +218,7 @@
 		std::list< Declaration* > members;
 		aggInst->lookup( name, members );
-		TypeSubstitution sub = TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->get_parameters().begin() );
 		for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
 			if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
-				MemberExpr * memExpr = new MemberExpr( dwt, expr->clone() );
-				sub.apply( memExpr );
-				alternatives.push_back( Alternative( memExpr, env, newCost ) );
+				alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) );
 				renameTypes( alternatives.back().expr );
 			} else {
Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/SymTab/Autogen.cc	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -175,8 +175,4 @@
 
 	void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, TypeSubstitution & genericSubs, bool isDynamicLayout, bool forward = true ) {
-// 		if ( isDynamicLayout && src ) {
-// 			genericSubs.apply( src );
-// 		}
-
 		ObjectDecl * returnVal = NULL;
 		if ( ! func->get_functionType()->get_returnVals().empty() ) {
@@ -187,13 +183,11 @@
 
 		// assign to destination (and return value if generic)
-		UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
-		derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
+		UntypedExpr *derefExpr = UntypedExpr::createDeref( new VariableExpr( dstParam ) );
 		Expression *dstselect = new MemberExpr( field, derefExpr );
 		genImplicitCall( srcParam, dstselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
 
 		if ( isDynamicLayout && returnVal ) {
-			UntypedExpr *derefRet = new UntypedExpr( new NameExpr( "*?" ) );
-			derefRet->get_args().push_back( new VariableExpr( returnVal ) );
-			Expression *retselect = new MemberExpr( field, derefRet );
+			// xxx - there used to be a dereference on returnVal, but this seems to have been wrong?
+			Expression *retselect = new MemberExpr( field, new VariableExpr( returnVal ) );
 			genImplicitCall( srcParam, retselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
 		} // if
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/SynTree/Expression.cc	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -332,8 +332,24 @@
 }
 
+namespace {
+	TypeSubstitution makeSub( Type * t ) {
+		if ( StructInstType * aggInst = dynamic_cast< StructInstType * >( t ) ) {
+			return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->get_parameters().begin() );
+		} else if ( UnionInstType * aggInst = dynamic_cast< UnionInstType * >( t ) ) {
+			return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->get_parameters().begin() );
+		} else {
+			assertf( false, "makeSub expects struct or union type for aggregate" );
+		}
+	}
+}
+
 
 MemberExpr::MemberExpr( DeclarationWithType *_member, Expression *_aggregate, Expression *_aname ) :
 		Expression( _aname ), member(_member), aggregate(_aggregate) {
-	set_result( member->get_type()->clone() );
+
+	TypeSubstitution sub( makeSub( aggregate->get_result() ) );
+	Type * res = member->get_type()->clone();
+	sub.apply( res );
+	set_result( res );
 	get_result()->set_isLvalue( true );
 }
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/Tuples/TupleExpansion.cc	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -93,5 +93,5 @@
 			typedef Mutator Parent;
 			using Parent::mutate;
-			
+
 			virtual Expression * mutate( TupleExpr * tupleExpr ) override;
 		};
@@ -218,19 +218,26 @@
 	Type * TupleTypeReplacer::mutate( TupleType * tupleType ) {
 		std::string mangleName = SymTab::Mangler::mangleType( tupleType );
-		TupleType * newType = safe_dynamic_cast< TupleType * > ( Parent::mutate( tupleType ) );
+		tupleType = safe_dynamic_cast< TupleType * > ( Parent::mutate( tupleType ) );
 		if ( ! typeMap.count( mangleName ) ) {
 			// generate struct type to replace tuple type
 			StructDecl * decl = new StructDecl( "_tuple_type_" + mangleName );
 			decl->set_body( true );
-			int cnt = 0;
-			for ( Type * t : *newType ) {
-				decl->get_members().push_back( new ObjectDecl( toString("field_", cnt++), DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, t->clone(), nullptr ) );
+			for ( size_t i = 0; i < tupleType->size(); ++i ) {
+				TypeDecl * tyParam = new TypeDecl( toString("tuple_param_", i), DeclarationNode::NoStorageClass, nullptr, TypeDecl::Any );
+				decl->get_members().push_back( new ObjectDecl( toString("field_", i), DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, new TypeInstType( Type::Qualifiers(), tyParam->get_name(), tyParam ), nullptr ) );
+				decl->get_parameters().push_back( tyParam );
 			}
 			typeMap[mangleName] = decl;
 			addDeclaration( decl );
 		}
-		Type::Qualifiers qualifiers = newType->get_qualifiers();
-		delete newType;
-		return new StructInstType( qualifiers, typeMap[mangleName] );
+		Type::Qualifiers qualifiers = tupleType->get_qualifiers();
+
+		StructDecl * decl = typeMap[mangleName];
+		StructInstType * newType = new StructInstType( qualifiers, decl );
+		for ( Type * t : *tupleType ) {
+			newType->get_parameters().push_back( new TypeExpr( t->clone() ) );
+		}
+		delete tupleType;
+		return newType;
 	}
 
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/main.cc	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -266,4 +266,6 @@
 		OPTPRINT( "expandUniqueExpr" ); // xxx - is this the right place for this? want to expand ASAP so that subsequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
 		Tuples::expandUniqueExpr( translationUnit );
+		OPTPRINT( "expandTuples" ); // xxx - is this the right place for this?
+		Tuples::expandTuples( translationUnit );
 
 		OPTPRINT("instantiateGenerics")
@@ -282,6 +284,4 @@
 		OPTPRINT( "box" )
 		GenPoly::box( translationUnit );
-		OPTPRINT( "expandTuples" ); // xxx - is this the right place for this?
-		Tuples::expandTuples( translationUnit );
 
 		// print tree right before code generation
Index: src/tests/tupleFunction.c
===================================================================
--- src/tests/tupleFunction.c	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/tests/tupleFunction.c	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
@@ -51,18 +51,10 @@
 }
 
-// forall(otype T | { T ?+?(T, T); })
-// [T, T, T] ?+?([T, T, T] x, [T, T, T] y) {
-// 	T x1, x2, x3, y1, y2, y3;
-// 	[x1, x2, x3] = x;
-// 	[y1, y2, y3] = y;
-// 	return [x1+y1, x2+y2, x3+y3];
-// }
+int main() {
+	[int, double, int] x = [777, 2.76, 8675];
+	int x1 = 123, x3 = 456;
+	double x2 = 999.123;
 
-int main() {
-  [int, double, int] x = [777, 2.76, 8675];
-  int x1 = 123, x3 = 456;
-  double x2 = 999.123;
-
-  printf("foo(...)=%d\n", foo(x1, x3, x2, (S){ 321, 654, 'Q', 3.14 }));
+	printf("foo(...)=%d\n", foo(x1, x3, x2, (S){ 321, 654, 'Q', 3.14 }));
 
 	// call function with tuple parameter using tuple variable arg
@@ -91,4 +83,12 @@
 	[x1, x2, x3] = quux();
 	printf("x1=%d x2=%lg x3=%d\n", x1, x2, x3);
+
+	// xxx - tuples of type parameters should come out as generic types?
+	// [x1, x2, x3] = ([(int)x1, (int)x2, (int)x3]) + ([(int)1, (int)2, (int)3]);
+	// ([(int)x1, (int)x2, (int)x3]) + ([(int)1, (int)2, (int)3]);
+	// printf("%d %g %d\n", x1, x2, x3);
+
+	// xxx - comes out the back as a cast, but should come out as a tuple expression of the first n fields cast to each of the result types
+	// ([int, double])x;
 }
 
