Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision d76c588058daa6269114595a571223a110ced0ab)
+++ src/ResolvExpr/Resolver.cc	(revision 99d45847f7626033f67b33afdf3e149972c747b0)
@@ -21,4 +21,6 @@
 #include "Alternative.h"                 // for Alternative, AltList
 #include "AlternativeFinder.h"           // for AlternativeFinder, resolveIn...
+#include "Candidate.hpp"
+#include "CandidateFinder.hpp"
 #include "CurrentObject.h"               // for CurrentObject
 #include "RenameVars.h"                  // for RenameVars, global_renamer
@@ -27,5 +29,8 @@
 #include "typeops.h"                     // for extractResultType
 #include "Unify.h"                       // for unify
+#include "AST/Decl.hpp"
+#include "AST/Init.hpp"
 #include "AST/Pass.hpp"
+#include "AST/Print.hpp"
 #include "AST/SymbolTable.hpp"
 #include "Common/PassVisitor.h"          // for PassVisitor
@@ -45,4 +50,5 @@
 #include "SynTree/Visitor.h"             // for acceptAll, maybeAccept
 #include "Tuples/Tuples.h"
+#include "Validate/FindSpecialDecls.h"   // for SizeType
 
 using namespace std;
@@ -112,5 +118,5 @@
 
 	namespace {
-		struct DeleteFinder : public WithShortCircuiting	{
+		struct DeleteFinder_old : public WithShortCircuiting	{
 			DeletedExpr * delExpr = nullptr;
 			void previsit( DeletedExpr * expr ) {
@@ -126,5 +132,5 @@
 
 	DeletedExpr * findDeletedExpr( Expression * expr ) {
-		PassVisitor<DeleteFinder> finder;
+		PassVisitor<DeleteFinder_old> finder;
 		expr->accept( finder );
 		return finder.pass.delExpr;
@@ -132,5 +138,5 @@
 
 	namespace {
-		struct StripCasts {
+		struct StripCasts_old {
 			Expression * postmutate( CastExpr * castExpr ) {
 				if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {
@@ -145,5 +151,5 @@
 
 			static void strip( Expression *& expr ) {
-				PassVisitor<StripCasts> stripper;
+				PassVisitor<StripCasts_old> stripper;
 				expr = expr->acceptMutator( stripper );
 			}
@@ -153,5 +159,5 @@
 			expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;
 			env.makeSubstitution( *expr->env );
-			StripCasts::strip( expr ); // remove unnecessary casts that may be buried in an expression
+			StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression
 		}
 
@@ -237,5 +243,5 @@
 				winner.cost = winner.cvtCost;
 			}
-			
+
 			// produce ambiguous errors, if applicable
 			if ( winners.size() != 1 ) {
@@ -257,5 +263,5 @@
 
 			// xxx - check for ambiguous expressions
-			
+
 			// output selected choice
 			alt = std::move( choice );
@@ -421,5 +427,5 @@
 	void Resolver_old::handlePtrType( PtrType * type ) {
 		if ( type->get_dimension() ) {
-			findSingleExpression( type->dimension, SymTab::SizeType->clone(), indexer );
+			findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
 		}
 	}
@@ -446,5 +452,5 @@
 		// default value expressions have an environment which shouldn't be there and trips up 
 		// later passes.
-		// xxx - it might be necessary to somehow keep the information from this environment, but I 
+		// xxx - it might be necessary to somehow keep the information from this environment, but I
 		// can't currently see how it's useful.
 		for ( Declaration * d : functionDecl->type->parameters ) {
@@ -797,11 +803,11 @@
 		initExpr->expr = nullptr;
 		std::swap( initExpr->env, newExpr->env );
-		// InitExpr may have inferParams in the case where the expression specializes a function 
-		// pointer, and newExpr may already have inferParams of its own, so a simple swap is not 
+		// InitExpr may have inferParams in the case where the expression specializes a function
+		// pointer, and newExpr may already have inferParams of its own, so a simple swap is not
 		// sufficient.
 		newExpr->spliceInferParams( initExpr );
 		delete initExpr;
 
-		// get the actual object's type (may not exactly match what comes back from the resolver 
+		// get the actual object's type (may not exactly match what comes back from the resolver
 		// due to conversions)
 		Type * initContext = currentObject.getCurrentType();
@@ -816,5 +822,5 @@
 					if ( isCharType( pt->get_base() ) ) {
 						if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {
-							// strip cast if we're initializing a char[] with a char *, 
+							// strip cast if we're initializing a char[] with a char *,
 							// e.g.  char x[] = "hello";
 							newExpr = ce->get_arg();
@@ -839,9 +845,9 @@
 		// move cursor into brace-enclosed initializer-list
 		currentObject.enterListInit();
-		// xxx - fix this so that the list isn't copied, iterator should be used to change current 
+		// xxx - fix this so that the list isn't copied, iterator should be used to change current
 		// element
 		std::list<Designation *> newDesignations;
 		for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {
-			// iterate designations and initializers in pairs, moving the cursor to the current 
+			// iterate designations and initializers in pairs, moving the cursor to the current
 			// designated object and resolving the initializer against that object.
 			Designation * des = std::get<0>(p);
@@ -936,38 +942,219 @@
 	///////////////////////////////////////////////////////////////////////////
 
+	namespace {
+		/// Finds deleted expressions in an expression tree
+		struct DeleteFinder_new final : public ast::WithShortCircuiting {
+			const ast::DeletedExpr * delExpr = nullptr;
+
+			void previsit( const ast::DeletedExpr * expr ) {
+				if ( delExpr ) { visit_children = false; }
+				else { delExpr = expr; }
+			}
+
+			void previsit( const ast::Expr * ) {
+				if ( delExpr ) { visit_children = false; }
+			}
+		};
+
+		/// Check if this expression is or includes a deleted expression
+		const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
+			ast::Pass<DeleteFinder_new> finder;
+			expr->accept( finder );
+			return finder.pass.delExpr;
+		}
+
+		/// Calls the CandidateFinder and finds the single best candidate
+		CandidateRef findUnfinishedKindExpression(
+			const ast::Expr * untyped, const ast::SymbolTable & symtab, const std::string & kind, 
+			std::function<bool(const Candidate &)> pred, ResolvMode mode = {}
+		) {
+			if ( ! untyped ) return nullptr;
+
+			// xxx - this isn't thread-safe, but should work until we parallelize the resolver
+			static unsigned recursion_level = 0;
+
+			++recursion_level;
+			ast::TypeEnvironment env;
+			CandidateFinder finder{ symtab, env };
+			finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
+			--recursion_level;
+
+			// produce a filtered list of candidates
+			CandidateList candidates;
+			for ( auto & cand : finder.candidates ) {
+				if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
+			}
+
+			// produce invalid error if no candidates
+			if ( candidates.empty() ) {
+				SemanticError( untyped, 
+					toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""), 
+					"expression: ") );
+			}
+
+			// search for cheapest candidate
+			CandidateList winners;
+			bool seen_undeleted = false;
+			for ( CandidateRef & cand : candidates ) {
+				int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
+
+				if ( c > 0 ) continue;  // skip more expensive than winner
+
+				if ( c < 0 ) {
+					// reset on new cheapest
+					seen_undeleted = ! findDeletedExpr( cand->expr );
+					winners.clear();
+				} else /* if ( c == 0 ) */ {
+					if ( findDeletedExpr( cand->expr ) ) {
+						// skip deleted expression if already seen one equivalent-cost not
+						if ( seen_undeleted ) continue;
+					} else if ( ! seen_undeleted ) {
+						// replace list of equivalent-cost deleted expressions with one non-deleted
+						winners.clear();
+						seen_undeleted = true;
+					}
+				}
+
+				winners.emplace_back( std::move( cand ) );
+			}
+
+			// promote candidate.cvtCost to .cost
+			for ( CandidateRef & cand : winners ) {
+				cand->cost = cand->cvtCost;
+			}
+
+			// produce ambiguous errors, if applicable
+			if ( winners.size() != 1 ) {
+				std::ostringstream stream;
+				stream << "Cannot choose between " << winners.size() << " alternatives for " 
+					<< kind << (kind != "" ? " " : "") << "expression\n";
+				ast::print( stream, untyped );
+				stream << " Alternatives are:\n";
+				print( stream, winners, 1 );
+				SemanticError( untyped->location, stream.str() );
+			}
+
+			// single selected choice
+			CandidateRef & choice = winners.front();
+
+			// fail on only expression deleted
+			if ( ! seen_undeleted ) {
+				SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
+				"includes deleted identifier in " );
+			}
+
+			return std::move( choice );
+		}
+
+		/// Strips extraneous casts out of an expression
+		struct StripCasts_new final {
+			const ast::Expr * postmutate( const ast::CastExpr * castExpr ) {
+				if ( 
+					castExpr->isGenerated 
+					&& typesCompatible( castExpr->arg->result, castExpr->result ) 
+				) {
+					// generated cast is the same type as its argument, remove it after keeping env
+					ast::ptr<ast::Expr> arg = castExpr->arg;
+					arg.get_and_mutate()->env = castExpr->env;
+					return arg;
+				}
+				return castExpr;
+			}
+
+			static void strip( ast::ptr< ast::Expr > & expr ) {
+				ast::Pass< StripCasts_new > stripper;
+				expr = expr->accept( stripper );
+			}
+		};
+
+		/// Establish post-resolver invariants for expressions
+		void finishExpr( 
+			ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env, 
+			const ast::TypeSubstitution * oldenv = nullptr
+		) {
+			// set up new type substitution for expression
+			ast::ptr< ast::TypeSubstitution > newenv = 
+				 oldenv ? oldenv : new ast::TypeSubstitution{};
+			env.writeToSubstitution( *newenv.get_and_mutate() );
+			expr.get_and_mutate()->env = std::move( newenv );
+			// remove unncecessary casts
+			StripCasts_new::strip( expr );
+		}
+		
+		/// resolve `untyped` to the expression whose candidate satisfies `pred` with the 
+		/// lowest cost, returning the resolved version
+		ast::ptr< ast::Expr > findKindExpression(
+			const ast::Expr * untyped, const ast::SymbolTable & symtab, const std::string & kind, 
+			std::function<bool(const Candidate &)> pred, ResolvMode mode = {}
+		) {
+			if ( ! untyped ) return {};
+			CandidateRef choice = 
+				findUnfinishedKindExpression( untyped, symtab, kind, pred, mode );
+			finishExpr( choice->expr, choice->env, untyped->env );
+			return std::move( choice->expr );
+		}
+
+		/// Predicate for "Candidate has integral type"
+		bool hasIntegralType( const Candidate & i ) {
+			const ast::Type * type = i.expr->result;
+			
+			if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
+				return bt->isInteger();
+			} else if ( 
+				dynamic_cast< const ast::EnumInstType * >( type ) 
+				|| dynamic_cast< const ast::ZeroType * >( type )
+				|| dynamic_cast< const ast::OneType * >( type )
+			) {
+				return true;
+			} else return false;
+		}
+
+		/// Resolve `untyped` as an integral expression, returning the resolved version
+		ast::ptr< ast::Expr > findIntegralExpression( 
+			const ast::Expr * untyped, const ast::SymbolTable & symtab 
+		) {
+			return findKindExpression( untyped, symtab, "condition", hasIntegralType );
+		}
+	}
+
 	class Resolver_new final 
-	: public ast::WithIndexer, public ast::WithGuards, public ast::WithVisitorRef<Resolver_new>, 
-	  public ast::WithShortCircuiting, public ast::WithStmtsToAdd<> {
-		  
+	: public ast::WithSymbolTable, public ast::WithGuards, 
+	  public ast::WithVisitorRef<Resolver_new>, public ast::WithShortCircuiting, 
+	  public ast::WithStmtsToAdd<> {
+	
+		ast::ptr< ast::Type > functionReturn = nullptr;
+		// ast::CurrentObject currentObject = nullptr;
+		bool inEnumDecl = false;
+
 	public: 
 		Resolver_new() = default;
-		Resolver_new( const ast::SymbolTable & syms ) { /*symtab = syms;*/ }
-
-		void previsit( ast::FunctionDecl * functionDecl );
-		ast::DeclWithType * postvisit( ast::FunctionDecl * functionDecl );
-		void previsit( ast::ObjectDecl * objectDecl );
-		void previsit( ast::EnumDecl * enumDecl );
-		void previsit( ast::StaticAssertDecl * assertDecl );
-
-		void previsit( ast::ArrayType * at );
-		void previsit( ast::PointerType * pt );
-
-		void previsit( ast::ExprStmt * exprStmt );
-		void previsit( ast::AsmExpr * asmExpr );
-		void previsit( ast::AsmStmt * asmStmt );
-		void previsit( ast::IfStmt * ifStmt );
-		void previsit( ast::WhileStmt * whileStmt );
-		void previsit( ast::ForStmt * forStmt );
-		void previsit( ast::SwitchStmt * switchStmt );
-		void previsit( ast::CaseStmt * caseStmt );
-		void previsit( ast::BranchStmt * branchStmt );
-		void previsit( ast::ReturnStmt * returnStmt );
-		void previsit( ast::ThrowStmt * throwStmt );
-		void previsit( ast::CatchStmt * catchStmt );
-		void previsit( ast::WaitForStmt * stmt );
-
-		void previsit( ast::SingleInit * singleInit );
-		void previsit( ast::ListInit * listInit );
-		void previsit( ast::ConstructorInit * ctorInit );
+		Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
+
+		void previsit( const ast::FunctionDecl * );
+		const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
+		void previsit( const ast::ObjectDecl * );
+		void previsit( const ast::EnumDecl * );
+		const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
+
+		void previsit( const ast::ArrayType * );
+		void previsit( const ast::PointerType * );
+
+		void previsit( const ast::ExprStmt * );
+		void previsit( const ast::AsmExpr * );
+		void previsit( const ast::AsmStmt * );
+		void previsit( const ast::IfStmt * );
+		void previsit( const ast::WhileStmt * );
+		void previsit( const ast::ForStmt * );
+		void previsit( const ast::SwitchStmt * );
+		void previsit( const ast::CaseStmt * );
+		void previsit( const ast::BranchStmt * );
+		void previsit( const ast::ReturnStmt * );
+		void previsit( const ast::ThrowStmt * );
+		void previsit( const ast::CatchStmt * );
+		void previsit( const ast::WaitForStmt * );
+
+		void previsit( const ast::SingleInit * );
+		void previsit( const ast::ListInit * );
+		void previsit( const ast::ConstructorInit * );
 	};
 
@@ -977,18 +1164,32 @@
 	}
 
-	void previsit( ast::FunctionDecl * functionDecl ) {
-		#warning unimplemented; Resolver port in progress
-		(void)functionDecl;
-		assert(false);
-	}
-
-	ast::DeclWithType * postvisit( ast::FunctionDecl * functionDecl ) {
-		#warning unimplemented; Resolver port in progress
-		(void)functionDecl;
-		assert(false);
-		return nullptr;
-	}
-
-	void previsit( ast::ObjectDecl * objectDecl ) {
+	void Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
+		GuardValue( functionReturn );
+		functionReturn = extractResultType( functionDecl->type );
+	}
+
+	const ast::FunctionDecl * Resolver_new::postvisit( const ast::FunctionDecl * functionDecl ) {
+		// default value expressions have an environment which shouldn't be there and trips up 
+		// later passes.
+		ast::ptr< ast::FunctionDecl > ret = functionDecl;
+		for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {
+			const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i];
+			
+			if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {
+				if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
+					if ( init->value->env == nullptr ) continue;
+					// clone initializer minus the initializer environment
+					strict_dynamic_cast< ast::SingleInit * >(
+						strict_dynamic_cast< ast::ObjectDecl * >( 
+							ret.get_and_mutate()->type.get_and_mutate()->params[i].get_and_mutate()
+						)->init.get_and_mutate()
+					)->value.get_and_mutate()->env = nullptr;
+				}
+			}
+		}
+		return ret.get();
+	}
+
+	void Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
 		#warning unimplemented; Resolver port in progress
 		(void)objectDecl;
@@ -996,17 +1197,22 @@
 	}
 
-	void previsit( ast::EnumDecl * enumDecl ) {
-		#warning unimplemented; Resolver port in progress
-		(void)enumDecl;
-		assert(false);
-	}
-
-	void previsit( ast::StaticAssertDecl * assertDecl ) {
-		#warning unimplemented; Resolver port in progress
-		(void)assertDecl;
-		assert(false);
-	}
-
-	void previsit( ast::ArrayType * at ) {
+	void Resolver_new::previsit( const ast::EnumDecl * ) {
+		// in case we decide to allow nested enums
+		GuardValue( inEnumDecl );
+		inEnumDecl = false;
+	}
+
+	const ast::StaticAssertDecl * Resolver_new::previsit( 
+		const ast::StaticAssertDecl * assertDecl 
+	) {
+		ast::ptr< ast::Expr > cond = findIntegralExpression( assertDecl->cond, symtab );
+		if ( cond == assertDecl->cond ) return assertDecl;
+		
+		ast::StaticAssertDecl * ret = mutate( assertDecl );
+		ret->cond = cond;
+		return ret;
+	}
+
+	void Resolver_new::previsit( const ast::ArrayType * at ) {
 		#warning unimplemented; Resolver port in progress
 		(void)at;
@@ -1014,5 +1220,5 @@
 	}
 
-	void previsit( ast::PointerType * pt ) {
+	void Resolver_new::previsit( const ast::PointerType * pt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)pt;
@@ -1020,5 +1226,5 @@
 	}
 
-	void previsit( ast::ExprStmt * exprStmt ) {
+	void Resolver_new::previsit( const ast::ExprStmt * exprStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)exprStmt;
@@ -1026,5 +1232,5 @@
 	}
 
-	void previsit( ast::AsmExpr * asmExpr ) {
+	void Resolver_new::previsit( const ast::AsmExpr * asmExpr ) {
 		#warning unimplemented; Resolver port in progress
 		(void)asmExpr;
@@ -1032,5 +1238,5 @@
 	}
 
-	void previsit( ast::AsmStmt * asmStmt ) {
+	void Resolver_new::previsit( const ast::AsmStmt * asmStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)asmStmt;
@@ -1038,5 +1244,5 @@
 	}
 
-	void previsit( ast::IfStmt * ifStmt ) {
+	void Resolver_new::previsit( const ast::IfStmt * ifStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)ifStmt;
@@ -1044,5 +1250,5 @@
 	}
 
-	void previsit( ast::WhileStmt * whileStmt ) {
+	void Resolver_new::previsit( const ast::WhileStmt * whileStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)whileStmt;
@@ -1050,5 +1256,5 @@
 	}
 
-	void previsit( ast::ForStmt * forStmt ) {
+	void Resolver_new::previsit( const ast::ForStmt * forStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)forStmt;
@@ -1056,5 +1262,5 @@
 	}
 
-	void previsit( ast::SwitchStmt * switchStmt ) {
+	void Resolver_new::previsit( const ast::SwitchStmt * switchStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)switchStmt;
@@ -1062,5 +1268,5 @@
 	}
 
-	void previsit( ast::CaseStmt * caseStmt ) {
+	void Resolver_new::previsit( const ast::CaseStmt * caseStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)caseStmt;
@@ -1068,5 +1274,5 @@
 	}
 
-	void previsit( ast::BranchStmt * branchStmt ) {
+	void Resolver_new::previsit( const ast::BranchStmt * branchStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)branchStmt;
@@ -1074,5 +1280,5 @@
 	}
 
-	void previsit( ast::ReturnStmt * returnStmt ) {
+	void Resolver_new::previsit( const ast::ReturnStmt * returnStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)returnStmt;
@@ -1080,5 +1286,5 @@
 	}
 
-	void previsit( ast::ThrowStmt * throwStmt ) {
+	void Resolver_new::previsit( const ast::ThrowStmt * throwStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)throwStmt;
@@ -1086,5 +1292,5 @@
 	}
 
-	void previsit( ast::CatchStmt * catchStmt ) {
+	void Resolver_new::previsit( const ast::CatchStmt * catchStmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)catchStmt;
@@ -1092,5 +1298,5 @@
 	}
 
-	void previsit( ast::WaitForStmt * stmt ) {
+	void Resolver_new::previsit( const ast::WaitForStmt * stmt ) {
 		#warning unimplemented; Resolver port in progress
 		(void)stmt;
@@ -1098,5 +1304,5 @@
 	}
 
-	void previsit( ast::SingleInit * singleInit ) {
+	void Resolver_new::previsit( const ast::SingleInit * singleInit ) {
 		#warning unimplemented; Resolver port in progress
 		(void)singleInit;
@@ -1104,5 +1310,5 @@
 	}
 
-	void previsit( ast::ListInit * listInit ) {
+	void Resolver_new::previsit( const ast::ListInit * listInit ) {
 		#warning unimplemented; Resolver port in progress
 		(void)listInit;
@@ -1110,5 +1316,5 @@
 	}
 
-	void previsit( ast::ConstructorInit * ctorInit ) {
+	void Resolver_new::previsit( const ast::ConstructorInit * ctorInit ) {
 		#warning unimplemented; Resolver port in progress
 		(void)ctorInit;
