Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 579263a52ab065d42a5208e15e3d707dd0d03798)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 933dbbdd51fba981922aaec1bce1f186615e9671)
@@ -809,4 +809,30 @@
 	}
 
+	Expression * restructureCast( Expression * argExpr, Type * toType ) {
+		if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() ) {
+			// Argument expression is a tuple and the target type is not void. Cast each member of the tuple
+			// to its corresponding target type, producing the tuple of those cast expressions. If there are
+			// more components of the tuple than components in the target type, then excess components do not
+			// come out in the result expression (but UniqueExprs ensure that side effects will still be done).
+			if ( Tuples::maybeImpure( argExpr ) && ! dynamic_cast< UniqueExpr * >( argExpr ) ) {
+				// expressions which may contain side effects require a single unique instance of the expression.
+				argExpr = new UniqueExpr( argExpr );
+			}
+			std::list< Expression * > componentExprs;
+			for ( unsigned int i = 0; i < toType->size(); i++ ) {
+				// cast each component
+				TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
+				componentExprs.push_back( restructureCast( idx, toType->getComponent( i ) ) );
+			}
+			delete argExpr;
+			assert( componentExprs.size() > 0 );
+			// produce the tuple of casts
+			return new TupleExpr( componentExprs );
+		} else {
+			// handle normally
+			return new CastExpr( argExpr, toType->clone() );
+		}
+	}
+
 	void AlternativeFinder::visit( CastExpr *castExpr ) {
 		Type *& toType = castExpr->get_result();
@@ -840,28 +866,5 @@
 				thisCost += Cost( 0, 0, discardedValues );
 
-				Expression * argExpr = i->expr->clone();
-				if ( argExpr->get_result()->size() > 1 && ! castExpr->get_result()->isVoid() ) {
-					// Argument expression is a tuple and the target type is not void. Cast each member of the tuple
-					// to its corresponding target type, producing the tuple of those cast expressions. If there are
-					// more components of the tuple than components in the target type, then excess components do not
-					// come out in the result expression (but UniqueExprs ensure that side effects will still be done).
-					if ( Tuples::maybeImpure( argExpr ) && ! dynamic_cast< UniqueExpr * >( argExpr ) ) {
-						// expressions which may contain side effects require a single unique instance of the expression.
-						argExpr = new UniqueExpr( argExpr );
-					}
-					std::list< Expression * > componentExprs;
-					for ( unsigned int i = 0; i < castExpr->get_result()->size(); i++ ) {
-						// cast each component
-						TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
-						componentExprs.push_back( new CastExpr( idx, castExpr->get_result()->getComponent( i )->clone() ) );
-					}
-					delete argExpr;
-					assert( componentExprs.size() > 0 );
-					// produce the tuple of casts
-					candidates.push_back( Alternative( new TupleExpr( componentExprs ), i->env, i->cost, thisCost ) );
-				} else {
-					// handle normally
-					candidates.push_back( Alternative( new CastExpr( argExpr->clone(), toType->clone() ), i->env, i->cost, thisCost ) );
-				}
+				candidates.push_back( Alternative( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost ) );
 			} // if
 		} // for
@@ -1183,31 +1186,39 @@
 
 	void AlternativeFinder::visit( UntypedInitExpr *initExpr ) {
-		AlternativeFinder finder( indexer, env );
-		finder.findWithAdjustment( initExpr->get_expr() );
-		// handle each option like a cast -- should probably push this info into AltFinder as a kind of expression, both to keep common code close and to have less 'reach-in', but more 'push-in'
+		// handle each option like a cast
 		AltList candidates;
-		std::cerr << "untyped init expr: " << initExpr << std::endl;
+		PRINT( std::cerr << "untyped init expr: " << initExpr << std::endl; )
 		// O(N^2) checks of d-types with e-types
-		for ( Alternative & alt : finder.get_alternatives() ) {
-			for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
+		for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
+			Type * toType = resolveTypeof( initAlt.type, indexer );
+			SymTab::validateType( toType, &indexer );
+			adjustExprType( toType, env, indexer );
+			// Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
+			// polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
+			// the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
+			AlternativeFinder finder( indexer, env );
+			finder.targetType = toType;
+			finder.findWithAdjustment( initExpr->get_expr() );
+			for ( Alternative & alt : finder.get_alternatives() ) {
+				TypeEnvironment newEnv( alt.env );
 				AssertionSet needAssertions, haveAssertions;
-				OpenVarSet openVars;
-				std::cerr << "  " << initAlt.type << " " << initAlt.designation << std::endl;
+				OpenVarSet openVars;  // find things in env that don't have a "representative type" and claim those are open vars?
+				PRINT( std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl; )
 				// It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
 				// cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
 				// that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
 				// to.
-				int discardedValues = alt.expr->get_result()->size() - initAlt.type->size();
+				int discardedValues = alt.expr->get_result()->size() - toType->size();
 				if ( discardedValues < 0 ) continue;
 				// xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
 				// allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
 				// unification run for side-effects
-				unify( initAlt.type, alt.expr->get_result(), alt.env, needAssertions, haveAssertions, openVars, indexer );
-
-				Cost thisCost = castCost( alt.expr->get_result(), initAlt.type, indexer, alt.env );
+				unify( toType, alt.expr->get_result(), newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
+
+				Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv );
 				if ( thisCost != Cost::infinity ) {
 					// count one safe conversion for each value that is thrown away
 					thisCost += Cost( 0, 0, discardedValues );
-					candidates.push_back( Alternative( new InitExpr( alt.expr->clone(), initAlt.type->clone(), initAlt.designation->clone() ), alt.env, alt.cost, thisCost ) );
+					candidates.push_back( Alternative( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost ) );
 				}
 			}
