Index: src/ResolvExpr/Candidate.hpp
===================================================================
--- src/ResolvExpr/Candidate.hpp	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/ResolvExpr/Candidate.hpp	(revision a2a85658cf6974dd82db6b96859293050e9fd3c0)
@@ -53,6 +53,6 @@
 	: expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {}
 
-	Candidate( const Candidate & o, const ast::Expr * x )
-	: expr( x ), cost( o.cost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ),
+	Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero )
+	: expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ),
 	  need( o.need ) {}
 
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision a2a85658cf6974dd82db6b96859293050e9fd3c0)
@@ -28,4 +28,5 @@
 #include "ExplodedArg.hpp"
 #include "Resolver.h"
+#include "ResolveTypeof.h"
 #include "SatisfyAssertions.hpp"
 #include "typeops.h"              // for adjustExprType, conversionCost, polyCost, specCost
@@ -38,4 +39,5 @@
 #include "AST/Type.hpp"
 #include "SymTab/Mangler.h"
+#include "SymTab/Validate.h"      // for validateType
 #include "Tuples/Tuples.h"        // for handleTupleAssignment
 
@@ -554,4 +556,12 @@
 	}
 
+	/// Generate a cast expression from `arg` to `toType`
+	const ast::Expr * restructureCast( const ast::Expr * arg, const ast::Type * toType, bool isGenerated ) {
+		#warning unimplemented
+		(void)arg; (void)toType; (void)isGenerated;
+		assert(false);
+		return nullptr;
+	}
+
 	/// Actually visits expressions to find their candidate interpretations
 	struct Finder final : public ast::WithShortCircuiting {
@@ -741,7 +751,37 @@
 		/// Adds implicit struct-conversions to the alternative list
 		void addAnonConversions( const CandidateRef & cand ) {
-			#warning unimplemented
-			(void)cand;
-			assert(false);
+			// adds anonymous member interpretations whenever an aggregate value type is seen. 
+			// it's okay for the aggregate expression to have reference type -- cast it to the 
+			// base type to treat the aggregate as the referenced value
+			ast::ptr< ast::Expr > aggrExpr( cand->expr );
+			ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
+			cand->env.apply( aggrType );
+			
+			if ( aggrType.as< ast::ReferenceType >() ) {
+				aggrExpr = 
+					new ast::CastExpr{ aggrExpr->location, aggrExpr, aggrType->stripReferences() };
+			}
+
+			if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
+				addAggMembers( structInst, aggrExpr, cand, Cost::safe, "" );
+			} else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
+				addAggMembers( unionInst, aggrExpr, cand, Cost::safe, "" );
+			}
+		}
+
+		/// Adds aggregate member interpretations
+		void addAggMembers( 
+			const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 
+			const CandidateRef & cand, const Cost & addedCost, const std::string & name 
+		) {
+			for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
+				auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
+				CandidateRef newCand = std::make_shared<Candidate>( 
+					*cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
+				// add anonymous member interpretations whenever an aggregate value type is seen 
+				// as a member expression
+				addAnonConversions( newCand );
+				candidates.emplace_back( move( newCand ) );
+			}
 		}
 
@@ -915,4 +955,52 @@
 
 		void postvisit( const ast::CastExpr * castExpr ) {
+			ast::ptr< ast::Type > toType = castExpr->result;
+			assert( toType );
+			toType = resolveTypeof( toType, symtab );
+			toType = SymTab::validateType( toType, symtab );
+			toType = adjustExprType( toType, tenv, symtab );
+
+			CandidateFinder finder{ symtab, tenv, toType };
+			finder.find( castExpr->arg, ResolvMode::withAdjustment() );
+
+			CandidateList matches;
+			for ( CandidateRef & cand : finder.candidates ) {
+				ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
+				ast::OpenVarSet open( cand->open );
+
+				cand->env.extractOpenVars( open );
+
+				// It is possible that a cast can throw away some values in a multiply-valued 
+				// expression, e.g. cast-to-void, 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 = cand->expr->result->size() - toType->size();
+				if ( discardedValues < 0 ) continue;
+
+				// unification run for side-effects
+				unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
+				Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env );
+				PRINT(
+					std::cerr << "working on cast with result: " << toType << std::endl;
+					std::cerr << "and expr type: " << cand->expr->result << std::endl;
+					std::cerr << "env: " << cand->env << std::endl;
+				)
+				if ( thisCost != Cost::infinity ) {
+					PRINT(
+						std::cerr << "has finite cost." << std::endl;
+					)
+					// count one safe conversion for each value that is thrown away
+					thisCost.incSafe( discardedValues );
+					CandidateRef newCand = std::make_shared<Candidate>( 
+						restructureCast( cand->expr, toType, castExpr->isGenerated ), 
+						copy( cand->env ), move( open ), move( need ), cand->cost, 
+						cand->cost + thisCost );
+					inferParameters( newCand, matches );
+				}
+			}
+
+			// castExpr->result should be replaced with toType
+			// candidates => matches
+
 			#warning unimplemented
 			(void)castExpr;
@@ -927,5 +1015,6 @@
 			for ( CandidateRef & r : finder.candidates ) {
 				addCandidate( 
-					*r, new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
+					*r, 
+					new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
 			}
 		}
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision a2a85658cf6974dd82db6b96859293050e9fd3c0)
@@ -27,11 +27,13 @@
 /// Data to perform expression resolution
 struct CandidateFinder {
-	CandidateList candidates;                ///< List of candidate resolutions
-	const ast::SymbolTable & symtab;         ///< Symbol table to lookup candidates
-	const ast::TypeEnvironment & env;        ///< Substitutions performed in this resolution
-	ast::ptr< ast::Type > targetType = nullptr;  ///< Target type for resolution
+	CandidateList candidates;          ///< List of candidate resolutions
+	const ast::SymbolTable & symtab;   ///< Symbol table to lookup candidates
+	const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
+	ast::ptr< ast::Type > targetType;  ///< Target type for resolution
 
-	CandidateFinder( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
-	: candidates(), symtab( symtab ), env( env ) {}
+	CandidateFinder( 
+		const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 
+		const ast::Type * tt = nullptr )
+	: candidates(), symtab( symtab ), env( env ), targetType( tt ) {}
 
 	/// Fill candidates with feasible resolutions for `expr`
Index: src/ResolvExpr/CastCost.cc
===================================================================
--- src/ResolvExpr/CastCost.cc	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/ResolvExpr/CastCost.cc	(revision a2a85658cf6974dd82db6b96859293050e9fd3c0)
@@ -78,5 +78,9 @@
 			});
 		} else {
-			PassVisitor<CastCost> converter( dest, indexer, env, castCost );
+			#warning cast on castCost artifact of having two functions, remove when port done
+			PassVisitor<CastCost> converter( 
+				dest, indexer, env, 
+				(Cost (*)( Type *, Type *, const SymTab::Indexer &, const TypeEnvironment & ))
+					castCost );
 			src->accept( converter );
 			if ( converter.pass.get_cost() == Cost::infinity ) {
@@ -125,4 +129,14 @@
 		}
 	}
+
+	Cost castCost( 
+		const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab, 
+		const ast::TypeEnvironment & env 
+	) {
+		#warning unimplmented
+		(void)src; (void)dst; (void)symtab; (void)env;
+		assert(false);
+		return Cost::zero;
+	}
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision a2a85658cf6974dd82db6b96859293050e9fd3c0)
@@ -107,4 +107,11 @@
 		return newType;
 	}
+
+	const ast::Type * resolveTypeof( const ast::Type * type , const ast::SymbolTable & symtab ) {
+		#warning unimplemented
+		(void)type; (void)symtab;
+		assert(false);
+		return nullptr;
+	}
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/ResolveTypeof.h
===================================================================
--- src/ResolvExpr/ResolveTypeof.h	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/ResolvExpr/ResolveTypeof.h	(revision a2a85658cf6974dd82db6b96859293050e9fd3c0)
@@ -20,7 +20,12 @@
 class Indexer;
 }  // namespace SymTab
+namespace ast {
+	class Type;
+	class SymbolTable;
+}
 
 namespace ResolvExpr {
 	Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
+	const ast::Type * resolveTypeof( const ast::Type *, const ast::SymbolTable & );
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/typeops.h
===================================================================
--- src/ResolvExpr/typeops.h	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/ResolvExpr/typeops.h	(revision a2a85658cf6974dd82db6b96859293050e9fd3c0)
@@ -78,4 +78,7 @@
 	// in CastCost.cc
 	Cost castCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env );
+	Cost castCost( 
+		const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab, 
+		const ast::TypeEnvironment & env );
 
 	// in ConversionCost.cc
