Index: src/GenPoly/InstantiateGeneric.cpp
===================================================================
--- src/GenPoly/InstantiateGeneric.cpp	(revision b1c220a2399317045242cbfc0393a483f0424241)
+++ src/GenPoly/InstantiateGeneric.cpp	(revision 185cd945998822778937f8929f8a9b2a7a011b5e)
@@ -42,4 +42,10 @@
 
 using type_vector = ast::vector< ast::TypeExpr >;
+
+template<typename C, typename V>
+bool contains( C const & container, V const & value ) {
+	return std::any_of( container.begin(), container.end(),
+			[value]( auto& element ){ return element == value; } );
+}
 
 /// Abstracts type equality for a list of parameter types.
@@ -423,5 +429,5 @@
 }
 
-struct GenericInstantiator final :
+class GenericInstantiator final :
 		public ast::WithCodeLocation,
 		public ast::WithConstTypeSubstitution,
@@ -444,4 +450,7 @@
 	/// member from an instantiation.
 	int memberIndex = -1;
+	/// The polymorphic types we are currently instantiating.
+	ast::vector<ast::Decl> instantiating;
+public:
 
 	GenericInstantiator() :
@@ -597,15 +606,20 @@
 			);
 
-			// Forward declare before recursion. (TODO: Only when needed, #199.)
+			// Insert the declaration so it doesn't create it again,
 			insert( inst, typeSubs, newDecl );
-			if ( AggrDecl const * forwardDecl = ast::asForward( newDecl ) ) {
-				declsToAddBefore.push_back( forwardDecl );
-			}
+			// ... but mark this declaration as one we are working on.
+			auto guard = makeFuncGuard(
+				[this, newDecl](){ instantiating.push_back( newDecl ); },
+				[this](){ instantiating.pop_back(); } );
 			// Recursively instantiate members:
 			concDecl = strict_dynamic_cast<AggrDecl const *>(
 				newDecl->accept( *visitor ) );
-			// Must occur before declaration is added so
-			// that member instantiation appear first.
+
+			// Produce the declaration after its members are instantiated.
 			declsToAddBefore.push_back( concDecl );
+		} else if ( contains( instantiating, concDecl ) ) {
+			if ( AggrDecl const * forwardDecl = ast::asForward( concDecl ) ) {
+				declsToAddBefore.push_back( forwardDecl );
+			}
 		}
 		return new ast::SueInstType<AggrDecl>( concDecl, inst->qualifiers );
Index: src/ResolvExpr/Resolver.cpp
===================================================================
--- src/ResolvExpr/Resolver.cpp	(revision b1c220a2399317045242cbfc0393a483f0424241)
+++ src/ResolvExpr/Resolver.cpp	(revision 185cd945998822778937f8929f8a9b2a7a011b5e)
@@ -703,6 +703,5 @@
 	} else {
 		if ( !objectDecl->isTypeFixed ) {
-			auto newDecl = fixObjectType(objectDecl, context);
-			auto mutDecl = mutate(newDecl);
+			objectDecl = fixObjectType(objectDecl, context);
 
 			// generate CtorInit wrapper when necessary.
@@ -710,21 +709,18 @@
 			// this object in visitor pass, thus disabling CtorInit codegen.
 			// this happens on aggregate members and function parameters.
-			if ( shouldGenCtorInit( mutDecl ) ) {
+			if ( shouldGenCtorInit( objectDecl ) ) {
 				// constructed objects cannot be designated
-				if ( InitTweak::isDesignated( mutDecl->init ) ) {
-					ast::Pass<ResolveDesignators> res( context );
-					maybe_accept( mutDecl->init.get(), res );
-					if ( !res.core.result ) {
-						SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object.\n"
-									   "If this is really what you want, initialize with @=." );
-					}
+				if ( InitTweak::isDesignated( objectDecl->init )
+						&& !ast::Pass<ResolveDesignators>::read(
+							objectDecl->init.get(), context ) ) {
+					SemanticError( objectDecl, "Cannot include designations in the initializer for a managed Object.\n"
+							"If this is really what you want, initialize with @=." );
 				}
 				// constructed objects should not have initializers nested too deeply
-				if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
-
-				mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
+				if ( !InitTweak::checkInitDepth( objectDecl ) ) SemanticError( objectDecl, "Managed object's initializer is too deep " );
+
+				objectDecl = ast::mutate_field( objectDecl, &ast::ObjectDecl::init,
+					InitTweak::genCtorInit( objectDecl->location, objectDecl ) );
 			}
-
-			objectDecl = mutDecl;
 		}
 		currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
Index: tests/.expect/functions.arm64.txt
===================================================================
--- tests/.expect/functions.arm64.txt	(revision b1c220a2399317045242cbfc0393a483f0424241)
+++ tests/.expect/functions.arm64.txt	(revision 185cd945998822778937f8929f8a9b2a7a011b5e)
@@ -139,5 +139,4 @@
 
 }
-struct _conc__tuple2_0;
 struct _conc__tuple2_0 {
     signed int field_0;
@@ -182,5 +181,4 @@
 
 }
-struct _conc__tuple3_1;
 struct _conc__tuple3_1 {
     signed int field_0;
@@ -202,5 +200,4 @@
     __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
 }
-struct _conc__tuple3_2;
 struct _conc__tuple3_2 {
     signed int field_0;
@@ -294,5 +291,4 @@
     __attribute__ ((unused)) signed int *const _X10_retval_f3KPi_1;
 }
-struct _conc__tuple2_3;
 struct _conc__tuple2_3 {
     signed int *field_0;
Index: tests/.expect/functions.x64.txt
===================================================================
--- tests/.expect/functions.x64.txt	(revision b1c220a2399317045242cbfc0393a483f0424241)
+++ tests/.expect/functions.x64.txt	(revision 185cd945998822778937f8929f8a9b2a7a011b5e)
@@ -139,5 +139,4 @@
 
 }
-struct _conc__tuple2_0;
 struct _conc__tuple2_0 {
     signed int field_0;
@@ -182,5 +181,4 @@
 
 }
-struct _conc__tuple3_1;
 struct _conc__tuple3_1 {
     signed int field_0;
@@ -202,5 +200,4 @@
     __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
 }
-struct _conc__tuple3_2;
 struct _conc__tuple3_2 {
     signed int field_0;
@@ -294,5 +291,4 @@
     __attribute__ ((unused)) signed int *const _X10_retval_f3KPi_1;
 }
-struct _conc__tuple2_3;
 struct _conc__tuple2_3 {
     signed int *field_0;
Index: tests/.expect/functions.x86.txt
===================================================================
--- tests/.expect/functions.x86.txt	(revision b1c220a2399317045242cbfc0393a483f0424241)
+++ tests/.expect/functions.x86.txt	(revision 185cd945998822778937f8929f8a9b2a7a011b5e)
@@ -139,5 +139,4 @@
 
 }
-struct _conc__tuple2_0;
 struct _conc__tuple2_0 {
     signed int field_0;
@@ -182,5 +181,4 @@
 
 }
-struct _conc__tuple3_1;
 struct _conc__tuple3_1 {
     signed int field_0;
@@ -202,5 +200,4 @@
     __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
 }
-struct _conc__tuple3_2;
 struct _conc__tuple3_2 {
     signed int field_0;
@@ -294,5 +291,4 @@
     __attribute__ ((unused)) signed int *const _X10_retval_f3KPi_1;
 }
-struct _conc__tuple2_3;
 struct _conc__tuple2_3 {
     signed int *field_0;
