Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision beabdf33ab61ce52710d5fc4be6faf28916576be)
+++ src/AST/Pass.impl.hpp	(revision 8472c6c4f495da4ee543c2f4abbb7586e0f3a4a0)
@@ -2042,5 +2042,4 @@
 	if ( __visit_children() ) {
 		maybe_accept( node, &TupleType::types );
-		maybe_accept( node, &TupleType::members );
 	}
 
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision beabdf33ab61ce52710d5fc4be6faf28916576be)
+++ src/AST/Type.cpp	(revision 8472c6c4f495da4ee543c2f4abbb7586e0f3a4a0)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 13 15:00:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Thu Nov 24  9:49:00 2022
-// Update Count     : 6
+// Last Modified On : Thu Apr  6 15:59:00 2023
+// Update Count     : 7
 //
 
@@ -199,23 +199,5 @@
 
 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
-: Type( q ), types( std::move(ts) ), members() {
-	// This constructor is awkward. `TupleType` needs to contain objects so that members can be
-	// named, but members without initializer nodes end up getting constructors, which breaks
-	// things. This happens because the object decls have to be visited so that their types are
-	// kept in sync with the types listed here. Ultimately, the types listed here should perhaps
-	// be eliminated and replaced with a list-view over members. The temporary solution is to
-	// make a `ListInit` with `maybeConstructed = false`, so when the object is visited it is not
-	// constructed. Potential better solutions include:
-	//   a) Separate `TupleType` from its declarations, into `TupleDecl` and `Tuple{Inst?}Type`,
-	//      similar to the aggregate types.
-	//   b) Separate initializer nodes better, e.g. add a `MaybeConstructed` node that is replaced
-	//      by `genInit`, rather than the current boolean flag.
-	members.reserve( types.size() );
-	for ( const Type * ty : types ) {
-		members.emplace_back( new ObjectDecl{
-			CodeLocation(), "", ty, new ListInit( CodeLocation(), {}, {}, NoConstruct ),
-			Storage::Classes{}, Linkage::Cforall } );
-	}
-}
+: Type( q ), types( std::move(ts) ) {}
 
 bool isUnboundType(const Type * type) {
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision beabdf33ab61ce52710d5fc4be6faf28916576be)
+++ src/AST/Type.hpp	(revision 8472c6c4f495da4ee543c2f4abbb7586e0f3a4a0)
@@ -10,6 +10,6 @@
 // Created On       : Thu May 9 10:00:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Thu Nov 24  9:47:00 2022
-// Update Count     : 8
+// Last Modified On : Thu Apr  6 15:58:00 2023
+// Update Count     : 9
 //
 
@@ -457,5 +457,4 @@
 public:
 	std::vector<ptr<Type>> types;
-	std::vector<ptr<Decl>> members;
 
 	TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} );
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision beabdf33ab61ce52710d5fc4be6faf28916576be)
+++ src/ResolvExpr/CurrentObject.cc	(revision 8472c6c4f495da4ee543c2f4abbb7586e0f3a4a0)
@@ -9,7 +9,7 @@
 // Author           : Rob Schluntz
 // Created On       : Tue Jun 13 15:28:32 2017
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul  1 09:16:01 2022
-// Update Count     : 15
+// Last Modified By : Andrew Beach
+// Last Modified On : Thu Apr  6 16:25:00 2023
+// Update Count     : 17
 //
 
@@ -593,4 +593,43 @@
 
 namespace ast {
+	/// Iterates members of a type by initializer.
+	class MemberIterator {
+	public:
+		virtual ~MemberIterator() {}
+
+		/// Internal set position based on iterator ranges.
+		virtual void setPosition(
+			std::deque< ptr< Expr > >::const_iterator it,
+			std::deque< ptr< Expr > >::const_iterator end ) = 0;
+
+		/// Walks the current object using the given designators as a guide.
+		void setPosition( const std::deque< ptr< Expr > > & designators ) {
+			setPosition( designators.begin(), designators.end() );
+		}
+
+		/// Retrieve the list of possible (Type,Designation) pairs for the
+		/// current position in the current object.
+		virtual std::deque< InitAlternative > operator* () const = 0;
+
+		/// True if the iterator is not currently at the end.
+		virtual operator bool() const = 0;
+
+		/// Moves the iterator by one member in the current object.
+		virtual MemberIterator & bigStep() = 0;
+
+		/// Moves the iterator by one member in the current subobject.
+		virtual MemberIterator & smallStep() = 0;
+
+		/// The type of the current object.
+		virtual const Type * getType() = 0;
+
+		/// The type of the current subobject.
+		virtual const Type * getNext() = 0;
+
+		/// Helper for operator*; aggregates must add designator to each init
+		/// alternative, but adding designators in operator* creates duplicates.
+		virtual std::deque< InitAlternative > first() const = 0;
+	};
+
 	/// create a new MemberIterator that traverses a type correctly
 	MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
@@ -684,6 +723,6 @@
 
 		void setPosition(
-			std::deque< ptr< Expr > >::const_iterator begin,
-			std::deque< ptr< Expr > >::const_iterator end
+			std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
+			std::deque<ast::ptr<ast::Expr>>::const_iterator end
 		) override {
 			if ( begin == end ) return;
@@ -899,9 +938,33 @@
 
 	class TupleIterator final : public AggregateIterator {
+		MemberList * memberList;
+
+		TupleIterator( const CodeLocation & loc,
+			const ast::TupleType * inst, MemberList * memberList )
+		: AggregateIterator(
+			loc, "TupleIterator", toString("Tuple", inst->size()), inst, *memberList
+		), memberList( memberList ) {}
+
+		// The two layer constructor, this helper and the destructor
+		// are all to pretend that Tuples have members (they do not).
+		static MemberList * newImaginaryMembers( const ast::TupleType * inst ) {
+			auto ret = new MemberList();
+			ret->reserve( inst->types.size() );
+			for ( const ast::Type * type : inst->types ) {
+				ret->emplace_back( new ast::ObjectDecl(
+					CodeLocation(), "", type,
+					new ast::ListInit( CodeLocation(), {}, {}, ast::NoConstruct )
+				) );
+			}
+			return ret;
+		}
+
 	public:
 		TupleIterator( const CodeLocation & loc, const TupleType * inst )
-		: AggregateIterator(
-			loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
-		) {}
+		: TupleIterator( loc, inst, newImaginaryMembers( inst ) ) {}
+
+		virtual ~TupleIterator() {
+			delete memberList;
+		}
 
 		operator bool() const override {
Index: src/ResolvExpr/CurrentObject.h
===================================================================
--- src/ResolvExpr/CurrentObject.h	(revision beabdf33ab61ce52710d5fc4be6faf28916576be)
+++ src/ResolvExpr/CurrentObject.h	(revision 8472c6c4f495da4ee543c2f4abbb7586e0f3a4a0)
@@ -9,7 +9,7 @@
 // Author           : Rob Schluntz
 // Created On       : Thu Jun  8 11:07:25 2017
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:36:48 2017
-// Update Count     : 3
+// Last Modified By : Andrew Beach
+// Last Modified On : Thu Apr  6 16:14:00 2023
+// Update Count     : 4
 //
 
@@ -65,41 +65,5 @@
 
 	/// Iterates members of a type by initializer
-	class MemberIterator {
-	public:
-		virtual ~MemberIterator() {}
-
-		/// Internal set position based on iterator ranges
-		virtual void setPosition( 
-			std::deque< ptr< Expr > >::const_iterator it, 
-			std::deque< ptr< Expr > >::const_iterator end ) = 0;
-
-		/// walks the current object using the given designators as a guide
-		void setPosition( const std::deque< ptr< Expr > > & designators ) {
-			setPosition( designators.begin(), designators.end() );
-		}
-
-		/// retrieve the list of possible (Type,Designation) pairs for the current position in the 
-		/// current object
-		virtual std::deque< InitAlternative > operator* () const = 0;
-
-		/// true if the iterator is not currently at the end
-		virtual operator bool() const = 0;
-
-		/// moves the iterator by one member in the current object
-		virtual MemberIterator & bigStep() = 0;
-
-		/// moves the iterator by one member in the current subobject
-		virtual MemberIterator & smallStep() = 0;
-
-		/// the type of the current object
-		virtual const Type * getType() = 0;
-
-		/// the type of the current subobject
-		virtual const Type * getNext() = 0;
-	
-		/// helper for operator*; aggregates must add designator to each init alternative, but 
-		/// adding designators in operator* creates duplicates
-		virtual std::deque< InitAlternative > first() const = 0;
-	};
+	class MemberIterator;
 
 	/// Builds initializer lists in resolution
