Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision c29d9ce432aee5b42e1d8d594682e2ece6c8008b)
+++ src/GenPoly/Box.cc	(revision 698664b31ec11656e60452a119fd6318d3f6b810)
@@ -414,5 +414,5 @@
 				for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) {
 					InferredParams::const_iterator inferParam = appExpr->get_inferParams().find( (*assert)->get_uniqueId() );
-					assert( inferParam != appExpr->get_inferParams().end() );
+					assert( inferParam != appExpr->get_inferParams().end() && "NOTE: Explicit casts of polymorphic functions to compatible monomorphic functions are currently unsupported" );
 					Expression *newExpr = inferParam->second.expr->clone();
 					addCast( newExpr, (*assert)->get_type(), tyVars );
Index: src/GenPoly/Specialize.cc
===================================================================
--- src/GenPoly/Specialize.cc	(revision c29d9ce432aee5b42e1d8d594682e2ece6c8008b)
+++ src/GenPoly/Specialize.cc	(revision 698664b31ec11656e60452a119fd6318d3f6b810)
@@ -45,4 +45,5 @@
 
 	  private:
+		Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams = 0 );
 		Expression *doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = 0 );
 		void handleExplicitParams( ApplicationExpr *appExpr );
@@ -61,4 +62,5 @@
 	}
 
+	/// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type.
 	bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
 		if ( env ) {
@@ -85,49 +87,81 @@
 	}
 
+	/// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise
+	FunctionType * getFunctionType( Type *ty ) {
+		PointerType *ptrType;
+		if ( ( ptrType = dynamic_cast< PointerType* >( ty ) ) ) {
+			return dynamic_cast< FunctionType* >( ptrType->get_base() ); // pointer if FunctionType, NULL otherwise
+		} else {
+			return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise
+		}
+	}
+
+	/// Generates a thunk that calls `actual` with type `funType` and returns its address
+	Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
+		FunctionType *newType = funType->clone();
+		if ( env ) {
+			TypeSubstitution newEnv( *env );
+			// it is important to replace only occurrences of type variables that occur free in the
+			// thunk's type
+			newEnv.applyFree( newType );
+		} // if
+		// create new thunk with same signature as formal type (C linkage, empty body)
+		FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( std::list< std::string >() ), false, false );
+		thunkFunc->fixUniqueId();
+
+		// thread thunk parameters into call to actual function, naming thunk parameters as we go
+		UniqueName paramNamer( paramPrefix );
+		ApplicationExpr *appExpr = new ApplicationExpr( actual );
+		for ( std::list< DeclarationWithType* >::iterator param = thunkFunc->get_functionType()->get_parameters().begin(); param != thunkFunc->get_functionType()->get_parameters().end(); ++param ) {
+			(*param )->set_name( paramNamer.newName() );
+			appExpr->get_args().push_back( new VariableExpr( *param ) );
+		} // for
+		appExpr->set_env( maybeClone( env ) );
+		if ( inferParams ) {
+			appExpr->get_inferParams() = *inferParams;
+		} // if
+
+		// handle any specializations that may still be present
+		std::string oldParamPrefix = paramPrefix;
+		paramPrefix += "p";
+		// save stmtsToAdd in oldStmts
+		std::list< Statement* > oldStmts;
+		oldStmts.splice( oldStmts.end(), stmtsToAdd );
+		handleExplicitParams( appExpr );
+		paramPrefix = oldParamPrefix;
+		// write any statements added for recursive specializations into the thunk body
+		thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );
+		// restore oldStmts into stmtsToAdd
+		stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );
+
+		// add return (or valueless expression) to the thunk
+		Statement *appStmt;
+		if ( funType->get_returnVals().empty() ) {
+			appStmt = new ExprStmt( noLabels, appExpr );
+		} else {
+			appStmt = new ReturnStmt( noLabels, appExpr );
+		} // if
+		thunkFunc->get_statements()->get_kids().push_back( appStmt );
+
+		// add thunk definition to queue of statements to add
+		stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );
+		// return address of thunk function as replacement expression
+		return new AddressExpr( new VariableExpr( thunkFunc ) );
+	}
+	
 	Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
 		if ( needsSpecialization( formalType, actual->get_results().front(), env ) ) {
-			PointerType *ptrType;
 			FunctionType *funType;
-			if ( ( ptrType = dynamic_cast< PointerType* >( formalType ) ) && ( funType = dynamic_cast< FunctionType* >( ptrType->get_base() ) ) ) {
-				FunctionType *newType = funType->clone();
-				if ( env ) {
-					TypeSubstitution newEnv( *env );
-					// it is important to replace only occurrences of type variables that occur free in the
-					// thunk's type
-					newEnv.applyFree( newType );
-				} // if
-				FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( std::list< std::string >() ), false, false );
-				thunkFunc->fixUniqueId();
-
-				UniqueName paramNamer( paramPrefix );
-				ApplicationExpr *appExpr = new ApplicationExpr( actual );
-				for ( std::list< DeclarationWithType* >::iterator param = thunkFunc->get_functionType()->get_parameters().begin(); param != thunkFunc->get_functionType()->get_parameters().end(); ++param ) {
-					(*param )->set_name( paramNamer.newName() );
-					appExpr->get_args().push_back( new VariableExpr( *param ) );
-				} // for
-				appExpr->set_env( maybeClone( env ) );
-				if ( inferParams ) {
-					appExpr->get_inferParams() = *inferParams;
-				} // if
-
-				// handle any specializations that may still be present
-				std::string oldParamPrefix = paramPrefix;
-				paramPrefix += "p";
-				std::list< Statement* > oldStmts;
-				oldStmts.splice( oldStmts.end(), stmtsToAdd );
-				handleExplicitParams( appExpr );
-				paramPrefix = oldParamPrefix;
-				thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );
-				stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );
-
-				Statement *appStmt;
-				if ( funType->get_returnVals().empty() ) {
-					appStmt = new ExprStmt( noLabels, appExpr );
+			if ( ( funType = getFunctionType( formalType ) ) ) {
+				ApplicationExpr *appExpr;
+				VariableExpr *varExpr;
+				if ( ( appExpr = dynamic_cast<ApplicationExpr*>( actual ) ) ) {
+					return createThunkFunction( funType, appExpr->get_function(), inferParams );
+				} else if ( ( varExpr = dynamic_cast<VariableExpr*>( actual ) ) ) {
+					return createThunkFunction( funType, varExpr, inferParams );
 				} else {
-					appStmt = new ReturnStmt( noLabels, appExpr );
-				} // if
-				thunkFunc->get_statements()->get_kids().push_back( appStmt );
-				stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );
-				return new AddressExpr( new VariableExpr( thunkFunc ) );
+					// This likely won't work, as anything that could build an ApplicationExpr probably hit one of the previous two branches
+					return createThunkFunction( funType, actual, inferParams );
+				}
 			} else {
 				return actual;
@@ -141,7 +175,6 @@
 		// create thunks for the explicit parameters
 		assert( ! appExpr->get_function()->get_results().empty() );
-		PointerType *pointer = dynamic_cast< PointerType* >( appExpr->get_function()->get_results().front() );
-		assert( pointer );
-		FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() );
+		FunctionType *function = getFunctionType( appExpr->get_function()->get_results().front() );
+		assert( function );
 		std::list< DeclarationWithType* >::iterator formal;
 		std::list< Expression* >::iterator actual;
@@ -173,6 +206,11 @@
 	Expression * Specialize::mutate( CastExpr *castExpr ) {
 		castExpr->get_arg()->acceptMutator( *this );
-		castExpr->set_arg( doSpecialization( castExpr->get_results().front(), castExpr->get_arg() ) );
-		return castExpr;
+		Expression *specialized = doSpecialization( castExpr->get_results().front(), castExpr->get_arg() );
+		if ( specialized != castExpr->get_arg() ) {
+			// assume here that the specialization incorporates the cast
+			return specialized;
+		} else {
+			return castExpr;
+		}
 	}
 
