Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision 8f9cc50b091ccf00d76ddcc332e7e31fe53bfaac)
+++ src/GenPoly/Box.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -1288,8 +1288,9 @@
 			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 );
 
 			if ( dynRetType ) {
-				ret = addDynRetParam( appExpr, function, dynRetType, arg );
+				ret = addDynRetParam( appExpr, function, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType
 			} else if ( needsAdapter( function, scopeTyVars ) ) {
 				// std::cerr << "needs adapter: ";
@@ -1301,5 +1302,5 @@
 			arg = appExpr->get_args().begin();
 
-			passTypeVars( appExpr, dynRetType, arg, exprTyVars );
+			passTypeVars( appExpr, concRetType, arg, exprTyVars ); // xxx - used to use dynRetType instead of concRetType
 			addInferredParams( appExpr, function, arg, exprTyVars );
 
@@ -1364,4 +1365,5 @@
 			// line below cloned from FixFunction.cc
 			// xxx - functionObj is never added to a list of declarations...
+			// alternatively, this function could return a new VariableExpr( functionDecl ) and change the result type of the new expression
 			ObjectDecl *functionObj = new ObjectDecl( functionDecl->get_name(), functionDecl->get_storageClass(), functionDecl->get_linkage(), 0,
 			                                          new PointerType( Type::Qualifiers(), functionDecl->get_type()->clone() ), 0 );
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision 8f9cc50b091ccf00d76ddcc332e7e31fe53bfaac)
+++ src/GenPoly/GenPoly.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -92,5 +92,5 @@
 	}
 
-	Type *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
+	ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
 		type = replaceTypeInst( type, env );
 
@@ -98,10 +98,10 @@
 			auto var = tyVars.find( typeInst->get_name() );
 			if ( var != tyVars.end() && var->second == TypeDecl::Any ) {
-				return type;
+				return typeInst;
 			}
 		} else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
-			if ( hasDynParams( structType->get_parameters(), tyVars, env ) ) return type;
+			if ( hasDynParams( structType->get_parameters(), tyVars, env ) ) return structType;
 		} else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
-			if ( hasDynParams( unionType->get_parameters(), tyVars, env ) ) return type;
+			if ( hasDynParams( unionType->get_parameters(), tyVars, env ) ) return unionType;
 		}
 		return 0;
Index: src/GenPoly/GenPoly.h
===================================================================
--- src/GenPoly/GenPoly.h	(revision 8f9cc50b091ccf00d76ddcc332e7e31fe53bfaac)
+++ src/GenPoly/GenPoly.h	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// GenPoly.h -- 
+// GenPoly.h --
 //
 // Author           : Richard C. Bilson
@@ -34,13 +34,13 @@
 	/// Replaces a TypeInstType by its referrent in the environment, if applicable
 	Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
-	
+
 	/// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
 	Type *isPolyType( Type *type, const TypeSubstitution *env = 0 );
-	
+
 	/// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
 	Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
 
 	/// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
-	Type *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
+	ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
 
 	/// true iff function has dynamic-layout return type under the given type variable map
@@ -55,5 +55,5 @@
 	/// returns polymorphic type if is pointer to polymorphic type, NULL otherwise; will look up substitution in env if provided
 	Type *isPolyPtr( Type *type, const TypeSubstitution *env = 0 );
-	
+
 	/// returns polymorphic type if is pointer to polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
 	Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
@@ -76,5 +76,5 @@
 	/// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
 	void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
-	
+
 	/// Prints type variable map
 	void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );
@@ -82,5 +82,5 @@
 	/// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType().
 	inline std::string mangleType( Type *ty ) { return SymTab::Mangler::mangleType( ty ); }
-	
+
 	/// Gets the name of the sizeof parameter for the type, given its mangled name
 	inline std::string sizeofName( const std::string &name ) { return std::string( "_sizeof_" ) + name; }
@@ -94,5 +94,5 @@
 	/// Gets the name of the layout function for a given aggregate type, given its declaration
 	inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); }
-	
+
 } // namespace GenPoly
 
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 8f9cc50b091ccf00d76ddcc332e7e31fe53bfaac)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -218,7 +218,10 @@
 		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 ) ) {
-				alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) );
+				MemberExpr * memExpr = new MemberExpr( dwt, expr->clone() );
+				sub.apply( memExpr );
+				alternatives.push_back( Alternative( memExpr, env, newCost ) );
 				renameTypes( alternatives.back().expr );
 			} else {
@@ -800,5 +803,4 @@
 		AlternativeFinder funcFinder( indexer, env );
 		funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
-
 		for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
 			if ( StructInstType *structInst = dynamic_cast< StructInstType* >( agg->expr->get_result() ) ) {
Index: src/SynTree/ReferenceToType.cc
===================================================================
--- src/SynTree/ReferenceToType.cc	(revision 8f9cc50b091ccf00d76ddcc332e7e31fe53bfaac)
+++ src/SynTree/ReferenceToType.cc	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -46,12 +46,10 @@
 
 namespace {
-	void doLookup( const std::list< Declaration* > &members, const std::list< TypeDecl* > &parms, const std::list< Expression* > &args, const std::string &name, std::list< Declaration* > &foundDecls ) {
-		std::list< Declaration* > found;
+	void doLookup( const std::list< Declaration* > &members, const std::string &name, std::list< Declaration* > &foundDecls ) {
 		for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
 			if ( (*i)->get_name() == name ) {
-				found.push_back( *i );
+				foundDecls.push_back( *i );
 			} // if
 		} // for
-		applySubstitution( parms.begin(), parms.end(), args.begin(), found.begin(), found.end(), back_inserter( foundDecls ) );
 	}
 } // namespace
@@ -68,5 +66,5 @@
 void StructInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const {
 	assert( baseStruct );
-	doLookup( baseStruct->get_members(), baseStruct->get_parameters(), parameters, name, foundDecls );
+	doLookup( baseStruct->get_members(), name, foundDecls );
 }
 
@@ -94,5 +92,5 @@
 void UnionInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const {
 	assert( baseUnion );
-	doLookup( baseUnion->get_members(), baseUnion->get_parameters(), parameters, name, foundDecls );
+	doLookup( baseUnion->get_members(), name, foundDecls );
 }
 
Index: src/tests/.expect/simpleGenericTriple.txt
===================================================================
--- src/tests/.expect/simpleGenericTriple.txt	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/tests/.expect/simpleGenericTriple.txt	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -0,0 +1,1 @@
+132 1001 459
Index: src/tests/simpleGenericTriple.c
===================================================================
--- src/tests/simpleGenericTriple.c	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
+++ src/tests/simpleGenericTriple.c	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -0,0 +1,38 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// simpleGenericTriple.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Tue Nov 15 17:24:32 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Tue Nov 15 17:27:28 2016
+// Update Count     : 3
+//
+
+forall(otype T)
+struct T3 {
+	T f0, f1, f2;
+};
+
+forall(otype T | { T ?+?(T, T); })
+T3(T) ?+?(T3(T) x, T3(T) y) {
+	T3(T) z = { x.f0+y.f0, x.f1+y.f1, x.f2+y.f2 };
+	return z;
+}
+
+int main() {
+  int x1 = 123, x3 = 456;
+  double x2 = 999.123;
+  struct T3(int) L = { x1, x2, x3 };
+  struct T3(int) R = { 9, 2, 3 };
+  struct T3(int) ret = L+R;
+  printf("%d %d %d\n", ret.f0, ret.f1, ret.f2);
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: src/tests/tupleAssign.c
===================================================================
--- src/tests/tupleAssign.c	(revision 8f9cc50b091ccf00d76ddcc332e7e31fe53bfaac)
+++ src/tests/tupleAssign.c	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -1,2 +1,17 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tupleAssign.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Tue Nov 15 17:24:32 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Tue Nov 15 17:27:28 2016
+// Update Count     : 3
+//
+
 int main() {
 	{
@@ -39,2 +54,6 @@
 	}
 }
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: src/tests/tupleFunction.c
===================================================================
--- src/tests/tupleFunction.c	(revision 8f9cc50b091ccf00d76ddcc332e7e31fe53bfaac)
+++ src/tests/tupleFunction.c	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -1,2 +1,17 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tupleFunction.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Tue Nov 15 17:24:32 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Tue Nov 15 17:27:28 2016
+// Update Count     : 3
+//
+
 struct S {
 	int f1, f2;
@@ -77,2 +92,7 @@
 	printf("x1=%d x2=%lg x3=%d\n", x1, x2, x3);
 }
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
+
Index: src/tests/tupleMember.c
===================================================================
--- src/tests/tupleMember.c	(revision 8f9cc50b091ccf00d76ddcc332e7e31fe53bfaac)
+++ src/tests/tupleMember.c	(revision 33a7b6db7e7a3b3fa85ef51cb227fdc43223b1fd)
@@ -1,2 +1,17 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tupleFunction.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Tue Nov 15 17:24:32 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Tue Nov 15 17:27:28 2016
+// Update Count     : 3
+//
+
 void f() {
 	printf("called f!\n");
@@ -41,2 +56,6 @@
 	printf("v.[f1, i.[f2, f3], f4]=[%d, [%d, %d], %lg]\n", h().[f1, i.[f2, f3], f4]);
 }
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
