Index: src/SynTree/Constant.cc
===================================================================
--- src/SynTree/Constant.cc	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/Constant.cc	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Constant.cc -- 
+// Constant.cc --
 //
 // Author           : Richard C. Bilson
@@ -46,4 +46,14 @@
 }
 
+unsigned long long Constant::get_ival() const {
+	assertf( safe_dynamic_cast<BasicType*>(type)->isInteger(), "Attempt to retrieve ival from non-integer constant." );
+	return val.ival;
+}
+
+double Constant::get_dval() const {
+	assertf( ! safe_dynamic_cast<BasicType*>(type)->isInteger(), "Attempt to retrieve dval from integer constant." );
+	return val.dval;
+}
+
 void Constant::print( std::ostream &os ) const {
 	os << "(" << rep << " " << val.ival;
Index: src/SynTree/Constant.h
===================================================================
--- src/SynTree/Constant.h	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/Constant.h	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Constant.h -- 
+// Constant.h --
 //
 // Author           : Richard C. Bilson
@@ -32,4 +32,6 @@
 	std::string & get_value() { return rep; }
 	void set_value( std::string newValue ) { rep = newValue; }
+	unsigned long long get_ival() const;
+	double get_dval() const;
 
 	/// generates a boolean constant of the given bool
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/Expression.cc	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -21,11 +21,15 @@
 #include <iterator>
 
+#include "Declaration.h"
+#include "Expression.h"
+#include "Initializer.h"
+#include "Statement.h"
 #include "Type.h"
-#include "Initializer.h"
-#include "Expression.h"
-#include "Declaration.h"
-#include "Statement.h"
 #include "TypeSubstitution.h"
+#include "VarExprReplacer.h"
+
 #include "Common/utility.h"
+#include "Common/PassVisitor.h"
+
 #include "InitTweak/InitTweak.h"
 
@@ -681,6 +685,6 @@
 }
 
-InitExpr::InitExpr( Expression * expr, Type * type, Designation * designation ) : expr( expr ), designation( designation ) {
-	set_result( type );
+InitExpr::InitExpr( Expression * expr, Designation * designation ) : expr( expr ), designation( designation ) {
+	set_result( expr->get_result()->clone() );
 }
 InitExpr::InitExpr( const InitExpr & other ) : Expression( other ), expr( maybeClone( other.expr ) ), designation( maybeClone( other.designation) ) {}
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/Expression.h	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -776,5 +776,5 @@
 class InitExpr : public Expression {
 public:
-	InitExpr( Expression * expr, Type * type, Designation * designation );
+	InitExpr( Expression * expr, Designation * designation );
 	InitExpr( const InitExpr & other );
 	~InitExpr();
Index: src/SynTree/Initializer.cc
===================================================================
--- src/SynTree/Initializer.cc	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/Initializer.cc	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -65,6 +65,14 @@
 
 
-ListInit::ListInit( const std::list<Initializer*> &initializers, const std::list<Designation *> &designations, bool maybeConstructed )
-	: Initializer( maybeConstructed ), initializers( initializers ), designations( designations ) {
+ListInit::ListInit( const std::list<Initializer*> &inits, const std::list<Designation *> &des, bool maybeConstructed )
+	: Initializer( maybeConstructed ), initializers( inits ), designations( des ) {
+		// handle the common case where a ListInit is created without designations by making a list of empty designations with the same length as the initializer
+		if ( designations.empty() ) {
+			for ( auto & i : initializers ) {
+				(void)i;
+				designations.push_back( new Designation( {} ) );
+			}
+		}
+		assertf( initializers.size() == designations.size(), "Created ListInit with mismatching initializers (%d) and designations (%d)", initializers.size(), designations.size() );
 }
 
Index: src/SynTree/Mutator.cc
===================================================================
--- src/SynTree/Mutator.cc	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/Mutator.cc	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -515,4 +515,5 @@
 	mutateAll( tupleType->get_forall(), *this );
 	mutateAll( tupleType->get_types(), *this );
+	mutateAll( tupleType->get_members(), *this );
 	return tupleType;
 }
Index: src/SynTree/TupleType.cc
===================================================================
--- src/SynTree/TupleType.cc	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/TupleType.cc	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -14,16 +14,31 @@
 //
 
+#include "Declaration.h"
+#include "Initializer.h"
 #include "Type.h"
 #include "Common/utility.h"
+#include "Parser/LinkageSpec.h"
 
 TupleType::TupleType( const Type::Qualifiers &tq, const std::list< Type * > & types, const std::list< Attribute * > & attributes ) : Type( tq, attributes ), types( types ) {
+	for ( Type * t : *this ) {
+		// xxx - this is very awkward. TupleTypes should contain objects so that members can be named, but if they don't have an initializer node then
+		// they end up getting constructors, which end up being inserted causing problems. This happens because the object decls have to be visited so that
+		// their types are kept in sync with the types list here. Ultimately, the types list here should be eliminated and perhaps replaced with a list-view
+		// of the object types list, but I digress. The temporary solution here is to make a ListInit with maybeConstructed = false, that way even when the
+		// object is visited, it is never constructed. Ultimately, a better solution might be either:
+		// a) to separate TupleType from its declarations, into TupleDecl and Tuple{Inst?}Type, ala StructDecl and StructInstType
+		// b) separate initializer nodes better, e.g. add a MaybeConstructed node that is replaced by genInit, rather than what currently exists in a bool
+		members.push_back( new ObjectDecl( "" , Type::StorageClasses(), LinkageSpec::Cforall, nullptr, t->clone(), new ListInit( {}, {}, false ) ) );
+	}
 }
 
 TupleType::TupleType( const TupleType& other ) : Type( other ) {
 	cloneAll( other.types, types );
+	cloneAll( other.members, members );
 }
 
 TupleType::~TupleType() {
 	deleteAll( types );
+	deleteAll( members );
 }
 
Index: src/SynTree/Type.h
===================================================================
--- src/SynTree/Type.h	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/Type.h	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -481,5 +481,5 @@
 class TupleType : public Type {
   public:
-	TupleType( const Type::Qualifiers & tq, const std::list< Type * > & types = std::list< Type * >(), const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
+	TupleType( const Type::Qualifiers & tq, const std::list< Type * > & types, const std::list< Attribute * > & attributes = std::list< Attribute * >()  );
 	TupleType( const TupleType& );
 	virtual ~TupleType();
@@ -488,6 +488,10 @@
 	typedef value_type::iterator iterator;
 
-	std::list<Type*>& get_types() { return types; }
+	std::list<Type *> & get_types() { return types; }
 	virtual unsigned size() const { return types.size(); };
+
+	// For now, this is entirely synthetic -- tuple types always have unnamed members.
+	// Eventually, we may allow named tuples, in which case members should subsume types
+	std::list<Declaration *> & get_members() { return members; }
 
 	iterator begin() { return types.begin(); }
@@ -506,5 +510,6 @@
 	virtual void print( std::ostream & os, int indent = 0 ) const;
   private:
-	std::list<Type*> types;
+	std::list<Type *> types;
+	std::list<Declaration *> members;
 };
 
Index: src/SynTree/VarExprReplacer.cc
===================================================================
--- src/SynTree/VarExprReplacer.cc	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/VarExprReplacer.cc	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -14,14 +14,18 @@
 //
 
+#include "Declaration.h"
 #include "Expression.h"
 #include "VarExprReplacer.h"
 
-VarExprReplacer::VarExprReplacer( const DeclMap & declMap ) : declMap( declMap ) {}
+VarExprReplacer::VarExprReplacer( const DeclMap & declMap, bool debug ) : declMap( declMap ), debug( debug ) {}
 
 // replace variable with new node from decl map
 void VarExprReplacer::visit( VariableExpr * varExpr ) {
-  // xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
-  if ( declMap.count( varExpr->get_var() ) ) {
-    varExpr->set_var( declMap.at( varExpr->get_var() ) );
-  }
+	// xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
+	if ( declMap.count( varExpr->get_var() ) ) {
+		if ( debug ) {
+			std::cerr << "replacing variable reference: " << (void*)varExpr->get_var() << " " << varExpr->get_var() << " with " << (void*)declMap.at( varExpr->get_var() ) << " " << declMap.at( varExpr->get_var() ) << std::endl;
+		}
+		varExpr->set_var( declMap.at( varExpr->get_var() ) );
+	}
 }
Index: src/SynTree/VarExprReplacer.h
===================================================================
--- src/SynTree/VarExprReplacer.h	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/VarExprReplacer.h	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -27,6 +27,7 @@
 private:
 	const DeclMap & declMap;
+  bool debug;
 public:
-	VarExprReplacer( const DeclMap & declMap );
+	VarExprReplacer( const DeclMap & declMap, bool debug = false );
 
 	// replace variable with new node from decl map
Index: src/SynTree/Visitor.cc
===================================================================
--- src/SynTree/Visitor.cc	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/SynTree/Visitor.cc	(revision 6242335009c5d2ebee1bb50d1d228f5aacb0e5bd)
@@ -407,4 +407,5 @@
 	acceptAll( tupleType->get_forall(), *this );
 	acceptAll( tupleType->get_types(), *this );
+	acceptAll( tupleType->get_members(), *this );
 }
 
