Index: src/Parser/parser.cc
===================================================================
--- src/Parser/parser.cc	(revision 848ce7101657d18db026ce010e05ae0026f97f55)
+++ src/Parser/parser.cc	(revision bf32bb8a6509388bf221983b0b4c4c8620ff76b9)
@@ -1023,9 +1023,9 @@
 static const yytype_uint16 yyrline[] =
 {
-       0,   302,   302,   306,   313,   314,   315,   319,   320,   321,
-     325,   326,   330,   331,   335,   336,   340,   344,   345,   356,
-     358,   360,   362,   367,   368,   374,   378,   380,   382,   384,
-     386,   388,   390,   392,   394,   403,   404,   410,   411,   415,
-     416,   420,   424,   426,   428,   430,   435,   436,   440,   443,
+       0,   301,   301,   305,   312,   313,   314,   318,   319,   320,
+     324,   325,   329,   330,   334,   335,   339,   343,   344,   355,
+     357,   359,   361,   366,   367,   373,   377,   379,   381,   383,
+     385,   387,   389,   391,   393,   402,   403,   409,   410,   414,
+     415,   419,   422,   424,   426,   428,   433,   435,   440,   443,
      445,   447,   452,   465,   467,   469,   471,   473,   475,   477,
      479,   481,   483,   485,   492,   493,   499,   500,   501,   502,
@@ -4977,5 +4977,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 302 "parser.yy"
+#line 301 "parser.yy"
     { typedefTable.enterScope(); }
     break;
@@ -4984,5 +4984,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 306 "parser.yy"
+#line 305 "parser.yy"
     { typedefTable.leaveScope(); }
     break;
@@ -4991,19 +4991,19 @@
 
 /* Line 1806 of yacc.c  */
+#line 312 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_constantInteger( *(yyvsp[(1) - (1)].tok) ) ); }
+    break;
+
+  case 5:
+
+/* Line 1806 of yacc.c  */
 #line 313 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_constantInteger( *(yyvsp[(1) - (1)].tok) ) ); }
-    break;
-
-  case 5:
+    { (yyval.en) = new ExpressionNode( build_constantFloat( *(yyvsp[(1) - (1)].tok) ) ); }
+    break;
+
+  case 6:
 
 /* Line 1806 of yacc.c  */
 #line 314 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_constantFloat( *(yyvsp[(1) - (1)].tok) ) ); }
-    break;
-
-  case 6:
-
-/* Line 1806 of yacc.c  */
-#line 315 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_constantChar( *(yyvsp[(1) - (1)].tok) ) ); }
     break;
@@ -5012,5 +5012,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 340 "parser.yy"
+#line 339 "parser.yy"
     { (yyval.constant) = build_constantStr( *(yyvsp[(1) - (1)].str) ); }
     break;
@@ -5019,5 +5019,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 344 "parser.yy"
+#line 343 "parser.yy"
     { (yyval.str) = (yyvsp[(1) - (1)].tok); }
     break;
@@ -5026,5 +5026,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 346 "parser.yy"
+#line 345 "parser.yy"
     {
 			appendStr( (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].tok) );						// append 2nd juxtaposed string to 1st
@@ -5037,5 +5037,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 357 "parser.yy"
+#line 356 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (1)].tok) ) ); }
     break;
@@ -5044,5 +5044,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 359 "parser.yy"
+#line 358 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (1)].tok) ) ); }
     break;
@@ -5051,5 +5051,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 361 "parser.yy"
+#line 360 "parser.yy"
     { (yyval.en) = (yyvsp[(2) - (3)].en); }
     break;
@@ -5058,5 +5058,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 363 "parser.yy"
+#line 362 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_valexpr( (yyvsp[(2) - (3)].sn) ) ); }
     break;
@@ -5065,5 +5065,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 373 "parser.yy"
+#line 372 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_binary_val( OperKinds::Index, (yyvsp[(1) - (6)].en), (yyvsp[(4) - (6)].en) ) ); }
     break;
@@ -5072,5 +5072,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 375 "parser.yy"
+#line 374 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_func( (yyvsp[(1) - (4)].en), (yyvsp[(3) - (4)].en) ) ); }
     break;
@@ -5079,5 +5079,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 379 "parser.yy"
+#line 378 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (3)].en), build_varref( (yyvsp[(3) - (3)].tok) ) ) ); }
     break;
@@ -5086,5 +5086,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 381 "parser.yy"
+#line 380 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); }
     break;
@@ -5093,5 +5093,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 383 "parser.yy"
+#line 382 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (3)].en), build_constantInteger( *(yyvsp[(3) - (3)].tok) ) ) ); }
     break;
@@ -5100,5 +5100,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 385 "parser.yy"
+#line 384 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (3)].en), build_varref( (yyvsp[(3) - (3)].tok) ) ) ); }
     break;
@@ -5107,5 +5107,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 387 "parser.yy"
+#line 386 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); }
     break;
@@ -5114,5 +5114,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 389 "parser.yy"
+#line 388 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::IncrPost, (yyvsp[(1) - (2)].en) ) ); }
     break;
@@ -5121,5 +5121,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 391 "parser.yy"
+#line 390 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_unary_ptr( OperKinds::DecrPost, (yyvsp[(1) - (2)].en) ) ); }
     break;
@@ -5128,5 +5128,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 393 "parser.yy"
+#line 392 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_compoundLiteral( (yyvsp[(2) - (7)].decl), new InitializerNode( (yyvsp[(5) - (7)].in), true ) ) ); }
     break;
@@ -5135,5 +5135,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 395 "parser.yy"
+#line 394 "parser.yy"
     {
 			Token fn;
@@ -5146,5 +5146,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 405 "parser.yy"
+#line 404 "parser.yy"
     { (yyval.en) = (ExpressionNode *)( (yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) )); }
     break;
@@ -5153,5 +5153,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 410 "parser.yy"
+#line 409 "parser.yy"
     { (yyval.en) = 0; }
     break;
@@ -5160,41 +5160,48 @@
 
 /* Line 1806 of yacc.c  */
-#line 416 "parser.yy"
+#line 415 "parser.yy"
     { (yyval.en) = (ExpressionNode *)(yyvsp[(1) - (3)].en)->set_last( (yyvsp[(3) - (3)].en) ); }
     break;
 
-  case 41:
+  case 42:
 
 /* Line 1806 of yacc.c  */
 #line 423 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (3)].en), maybeMoveBuild<Expression>( (yyvsp[(3) - (3)].en) ) ) ); }
+    break;
+
+  case 43:
+
+/* Line 1806 of yacc.c  */
+#line 425 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); }
+    break;
+
+  case 44:
+
+/* Line 1806 of yacc.c  */
+#line 427 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (3)].en), maybeMoveBuild<Expression>( (yyvsp[(3) - (3)].en) ) ) ); }
+    break;
+
+  case 45:
+
+/* Line 1806 of yacc.c  */
+#line 429 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(1) - (7)].en), build_tuple( (yyvsp[(5) - (7)].en) ) ) ); }
+    break;
+
+  case 46:
+
+/* Line 1806 of yacc.c  */
+#line 434 "parser.yy"
     { (yyval.en) = new ExpressionNode( build_varref( (yyvsp[(1) - (1)].tok) ) ); }
     break;
 
-  case 42:
-
-/* Line 1806 of yacc.c  */
-#line 425 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(3) - (3)].en), build_varref( (yyvsp[(1) - (3)].tok) ) ) ); }
-    break;
-
-  case 43:
-
-/* Line 1806 of yacc.c  */
-#line 427 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_fieldSel( (yyvsp[(5) - (7)].en), build_varref( (yyvsp[(1) - (7)].tok) ) ) ); }
-    break;
-
-  case 44:
-
-/* Line 1806 of yacc.c  */
-#line 429 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(3) - (3)].en), build_varref( (yyvsp[(1) - (3)].tok) ) ) ); }
-    break;
-
-  case 45:
-
-/* Line 1806 of yacc.c  */
-#line 431 "parser.yy"
-    { (yyval.en) = new ExpressionNode( build_pfieldSel( (yyvsp[(5) - (7)].en), build_varref( (yyvsp[(1) - (7)].tok) ) ) ); }
+  case 47:
+
+/* Line 1806 of yacc.c  */
+#line 436 "parser.yy"
+    { (yyval.en) = new ExpressionNode( build_constantInteger( *(yyvsp[(1) - (1)].tok) ) ); }
     break;
 
@@ -9208,5 +9215,5 @@
 
 /* Line 1806 of yacc.c  */
-#line 9211 "Parser/parser.cc"
+#line 9218 "Parser/parser.cc"
       default: break;
     }
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 848ce7101657d18db026ce010e05ae0026f97f55)
+++ src/Parser/parser.yy	(revision bf32bb8a6509388bf221983b0b4c4c8620ff76b9)
@@ -195,6 +195,5 @@
 
 %type<decl> field_declaration field_declaration_list field_declarator field_declaring_list
-%type<en> field field_list
-%type<tok> field_name
+%type<en> field field_list field_name
 
 %type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr
@@ -421,18 +420,19 @@
 		// ambiguity with .0 so space required after field-selection, e.g.
 		//   struct S { int 0, 1; } s; s. 0 = 0; s. 1 = 1;
-		{ $$ = new ExpressionNode( build_varref( $1 ) ); }
 	| field_name '.' field
-		{ $$ = new ExpressionNode( build_fieldSel( $3, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_fieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
 	| field_name '.' '[' push field_list pop ']'
-		{ $$ = new ExpressionNode( build_fieldSel( $5, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $5 ) ) ); }
 	| field_name ARROW field
-		{ $$ = new ExpressionNode( build_pfieldSel( $3, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_pfieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
 	| field_name ARROW '[' push field_list pop ']'
-		{ $$ = new ExpressionNode( build_pfieldSel( $5, build_varref( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $5 ) ) ); }
 	;
 
 field_name:
 	no_attr_identifier
+		{ $$ = new ExpressionNode( build_varref( $1 ) ); }
 	| INTEGERconstant
+		{ $$ = new ExpressionNode( build_constantInteger( *$1 ) ); }
 	;
 
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 848ce7101657d18db026ce010e05ae0026f97f55)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision bf32bb8a6509388bf221983b0b4c4c8620ff76b9)
@@ -209,23 +209,17 @@
 	template< typename StructOrUnionType >
 	void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
-		// member must be either a tuple expression or a name expr
-		if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) {
-			const std::string & name = nameExpr->get_name();
-			std::list< Declaration* > members;
-			aggInst->lookup( name, members );
-			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 ) );
-					renameTypes( alternatives.back().expr );
-				} else {
-					assert( false );
-				}
-			}
-		} else if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( member ) ) {
-			assert( false );
-		} else {
-			// xxx - temporary
-			std::cerr << member << std::endl;
-			assertf( false, "reached unexpected case of addAggMembers" );
+
+		// by this point, member must be a name expr
+		NameExpr * nameExpr = safe_dynamic_cast< NameExpr * >( member );
+		const std::string & name = nameExpr->get_name();
+		std::list< Declaration* > members;
+		aggInst->lookup( name, members );
+		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 ) );
+				renameTypes( alternatives.back().expr );
+			} else {
+				assert( false );
+			}
 		}
 	}
@@ -1059,4 +1053,21 @@
 		alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
 	}
+
+	void AlternativeFinder::visit( UniqueExpr *unqExpr ) {
+		AlternativeFinder finder( indexer, env );
+		finder.findWithAdjustment( unqExpr->get_expr() );
+		for ( Alternative & alt : finder.alternatives ) {
+			// xxx - it's possible that this won't always do the right thing, i.e. two UniqueExprs
+			// with the same ID may resolve to different expressions. If this ever happens, it might be necessary
+			// to try to select an alternative here (i.e. error is there is not a unique min-cost expression).
+			// One other thought is to to resolve each ID once and map the IDs to resolved expressions,
+			// but this isn't as simple as it sounds since the alternative is not selected here, meaning it might
+			// require complicated tracking throughout the system.
+
+			// brand the new UniqueExprs with the same id so that they are recognized as the same expression by the expansion pass
+			alternatives.push_back( Alternative( new UniqueExpr( alt.expr->clone(), unqExpr->get_id() ), env, Cost::zero ) );
+		}
+	}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision 848ce7101657d18db026ce010e05ae0026f97f55)
+++ src/ResolvExpr/AlternativeFinder.h	(revision bf32bb8a6509388bf221983b0b4c4c8620ff76b9)
@@ -69,4 +69,5 @@
 		virtual void visit( TupleIndexExpr *tupleExpr );
 		virtual void visit( TupleAssignExpr *tupleExpr );
+		virtual void visit( UniqueExpr *unqExpr );
 		/// Runs a new alternative finder on each element in [begin, end)
 		/// and writes each alternative finder to out.
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 848ce7101657d18db026ce010e05ae0026f97f55)
+++ src/SynTree/Expression.cc	(revision bf32bb8a6509388bf221983b0b4c4c8620ff76b9)
@@ -580,11 +580,15 @@
 
 
-UniqueExpr::UniqueExpr( Expression *expr ) : expr( new Expression* ) {
+long long UniqueExpr::count = 0;
+UniqueExpr::UniqueExpr( Expression *expr, long long idVal ) : expr( new Expression* ), id( idVal ) {
+	assert( count != -1 );
+	if ( id == -1 ) id = count++;
 	set_expr( expr );
 	assert( expr );
-	assert( expr->has_result() );
-	set_result( expr->get_result()->clone() );
-}
-UniqueExpr::UniqueExpr( const UniqueExpr &other ) : Expression( other ), expr( other.expr ) {
+	if ( expr->get_result() ) {
+		set_result( expr->get_result()->clone() );
+	}
+}
+UniqueExpr::UniqueExpr( const UniqueExpr &other ) : Expression( other ), expr( other.expr ), id( other.id ) {
 }
 UniqueExpr::~UniqueExpr() {
@@ -594,5 +598,5 @@
 }
 void UniqueExpr::print( std::ostream &os, int indent ) const {
-	os << "Unique Expression: " << std::endl << std::string( indent+2, ' ' );
+	os << "Unique Expression with id:" << id << std::endl << std::string( indent+2, ' ' );
 	get_expr()->print( os, indent+2 );
 }
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 848ce7101657d18db026ce010e05ae0026f97f55)
+++ src/SynTree/Expression.h	(revision bf32bb8a6509388bf221983b0b4c4c8620ff76b9)
@@ -735,5 +735,5 @@
 class UniqueExpr : public Expression {
 public:
-	UniqueExpr( Expression * expr );
+	UniqueExpr( Expression * expr, long long idVal = -1 );
 	UniqueExpr( const UniqueExpr & other );
 	~UniqueExpr();
@@ -742,4 +742,6 @@
 	UniqueExpr * set_expr( Expression * newValue ) { *expr = newValue; return this; }
 
+	int get_id() const { return id; }
+
 	virtual UniqueExpr *clone() const { return new UniqueExpr( *this ); }
 	virtual void accept( Visitor &v ) { v.visit( this ); }
@@ -748,4 +750,6 @@
 private:
 	std::shared_ptr< Expression * > expr;
+	int id;
+	static long long count;
 };
 
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 848ce7101657d18db026ce010e05ae0026f97f55)
+++ src/Tuples/TupleExpansion.cc	(revision bf32bb8a6509388bf221983b0b4c4c8620ff76b9)
@@ -31,9 +31,15 @@
 namespace Tuples {
 	namespace {
+		class MemberTupleExpander : public Mutator {
+		public:
+			typedef Mutator Parent;
+			virtual Expression * mutate( UntypedMemberExpr * memberExpr );
+		};
+
 		class UniqueExprExpander : public GenPoly::DeclMutator {
 		public:
 			typedef GenPoly::DeclMutator Parent;
 			virtual Expression * mutate( UniqueExpr * unqExpr );
-			std::map< Expression *, ObjectDecl * > decls;
+			std::map< int, ObjectDecl * > decls; // not vector, because order added may not be increasing order
 		};
 
@@ -73,4 +79,9 @@
 	}
 
+	void expandMemberTuples( std::list< Declaration * > & translationUnit ) {
+		MemberTupleExpander expander;
+		mutateAll( translationUnit, expander );
+	}
+
 	void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {
 		UniqueExprExpander unqExpander;
@@ -92,14 +103,49 @@
 	}
 
+	namespace {
+		/// given a expression representing the member and an expression representing the aggregate,
+		/// reconstructs a flattened UntypedMemberExpr with the right precedence
+		Expression * reconstructMemberExpr( Expression * member, UniqueExpr * aggr ) {
+			if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {
+				// construct a new UntypedMemberExpr with the correct structure , and recursively
+				// expand that member expression.
+				MemberTupleExpander expander;
+				UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->get_member(), new UntypedMemberExpr( memberExpr->get_aggregate(), aggr->clone() ) );
+
+				memberExpr->set_member(nullptr);
+				memberExpr->set_aggregate(nullptr);
+				delete memberExpr;
+				return newMemberExpr->acceptMutator( expander );
+			} else {
+				// not a member expression, so there is nothing to do but attach and return
+				return new UntypedMemberExpr( member, aggr->clone() );
+			}
+		}
+	}
+
+	Expression * MemberTupleExpander::mutate( UntypedMemberExpr * memberExpr ) {
+		if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( memberExpr->get_member() ) ) {
+			UniqueExpr * unqExpr = new UniqueExpr( memberExpr->get_aggregate()->clone() );
+			for ( Expression *& expr : tupleExpr->get_exprs() ) {
+				expr = reconstructMemberExpr( expr, unqExpr );
+			}
+			delete unqExpr;
+			return tupleExpr;
+		} else {
+			return memberExpr;
+		}
+	}
+
 	Expression * UniqueExprExpander::mutate( UniqueExpr * unqExpr ) {
 		static UniqueName tempNamer( "_unq_expr_" );
 		unqExpr = safe_dynamic_cast< UniqueExpr * > ( Parent::mutate( unqExpr ) );
-		if ( ! decls.count( unqExpr->get_expr() ) ) {
+		if ( ! decls.count( unqExpr->get_id() ) ) {
 			// xxx - it's possible (likely?) that expressions can appear in the wrong order because of this. Need to ensure they're placed in the correct location.
+			// xxx - is it possible to make the decl's type const?
 			ObjectDecl * decl = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, unqExpr->get_result()->clone(), new SingleInit( unqExpr->get_expr()->clone() ) );
-			decls[unqExpr->get_expr()] = decl;
+			decls[unqExpr->get_id()] = decl;
 			addDeclaration( decl );
 		}
-		return new VariableExpr( decls[unqExpr->get_expr()] );
+		return new VariableExpr( decls[unqExpr->get_id()] );
 	}
 
@@ -176,8 +222,11 @@
 
 	Expression * TupleExprExpander::mutate( TupleExpr * tupleExpr ) {
+		// recursively expand sub-tuple-expressions
+		tupleExpr = safe_dynamic_cast<TupleExpr *>(Parent::mutate(tupleExpr));
 		Type * result = tupleExpr->get_result();
 		std::list< Expression * > exprs = tupleExpr->get_exprs();
 		assert( result );
 
+		// remove data from shell and delete it
 		tupleExpr->set_result( nullptr );
 		tupleExpr->get_exprs().clear();
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision 848ce7101657d18db026ce010e05ae0026f97f55)
+++ src/Tuples/Tuples.h	(revision bf32bb8a6509388bf221983b0b4c4c8620ff76b9)
@@ -30,12 +30,18 @@
 
 	// TupleExpansion.cc
+	/// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
+	void expandMemberTuples( std::list< Declaration * > & translationUnit );
+
+	/// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
 	void expandTuples( std::list< Declaration * > & translationUnit );
 
-  void expandUniqueExpr( std::list< Declaration * > & translationUnit );
+	/// replaces UniqueExprs with a temporary variable and one call
+	void expandUniqueExpr( std::list< Declaration * > & translationUnit );
 
-  /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
-  Type * makeTupleType( const std::list< Expression * > & exprs );
+	/// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
+	Type * makeTupleType( const std::list< Expression * > & exprs );
 
-  bool maybeImpure( Expression * expr );
+	/// returns true if the expression may contain side-effects.
+	bool maybeImpure( Expression * expr );
 
 
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 848ce7101657d18db026ce010e05ae0026f97f55)
+++ src/main.cc	(revision bf32bb8a6509388bf221983b0b4c4c8620ff76b9)
@@ -232,5 +232,6 @@
 		OPTPRINT( "tweakInit" )
 		InitTweak::genInit( translationUnit );
-
+		OPTPRINT( "expandMemberTuples" );
+		Tuples::expandMemberTuples( translationUnit );
 		if ( libcfap ) {
 			// generate the bodies of cfa library functions
