Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ libcfa/src/iostream.cfa	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -5,11 +5,11 @@
 // file "LICENCE" distributed with Cforall.
 //
-// iostream.c --
+// iostream.cfa --
 //
 // Author           : Peter A. Buhr
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Jun  9 16:27:17 2019
-// Update Count     : 803
+// Last Modified On : Wed Jun 12 15:00:31 2019
+// Update Count     : 819
 //
 
@@ -740,4 +740,14 @@
 	} // ?|?
 
+	istype & ?|?( istype & is, const char * fmt ) {
+		fmt( is, fmt, "" );
+		return is;
+	} // ?|?
+
+	istype & ?|?( istype & is, char * s ) {
+		fmt( is, "%s", s );
+		return is;
+	} // ?|?
+
 	// manipulators
 	istype & ?|?( istype & is, istype & (* manip)( istype & ) ) {
@@ -767,6 +777,7 @@
 	// skip xxx
 	if ( ! f.s ) {
-		// printf( "skip %s\n", f.scanset );
-		fmt( is, f.scanset, "" );						// no input arguments
+		//printf( "skip %s %d\n", f.scanset, f.wd );
+		if ( f.wd != -1 ) for ( f.wd ) fmt( is, "%*c" ); // no input arguments
+		else fmt( is, f.scanset, "" );
 		return is;
 	} // if
@@ -797,4 +808,10 @@
 } // ?|?
 
+forall( dtype istype | istream( istype ) )
+istype & ?|?( istype & is, _Istream_Char f ) {
+	fmt( is, "%*c" );									// argument variable unused
+	return is;
+} // ?|?
+
 #define InputFMTImpl( T, CODE ) \
 forall( dtype istype | istream( istype ) ) \
@@ -802,5 +819,5 @@
 	enum { size = 16 }; \
 	char fmtstr[size]; \
-	if ( f.wd == -1 || strcmp( CODE, "c" ) == 0 ) { /* ignore width with "c" */	\
+	if ( f.wd == -1 ) { \
 		snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \
 	} else { \
@@ -812,5 +829,4 @@
 } // ?|?
 
-InputFMTImpl( char, "c" )
 InputFMTImpl( signed char, "hhi" )
 InputFMTImpl( unsigned char, "hhi" )
Index: libcfa/src/iostream.hfa
===================================================================
--- libcfa/src/iostream.hfa	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ libcfa/src/iostream.hfa	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jun  8 17:28:44 2019
-// Update Count     : 312
+// Last Modified On : Wed Jun 12 13:35:42 2019
+// Update Count     : 331
 //
 
@@ -155,5 +155,5 @@
 struct _Ostream_Manip {
 	T val;												// polymorphic base-type
-	unsigned char wd, pc;								// width, precision
+	unsigned int wd, pc;								// width, precision
 	char base;											// numeric base / floating-point style
 	union {
@@ -180,8 +180,8 @@
 	_Ostream_Manip(T) oct( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'o', { .all : 0 } }; } \
 	_Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'x', { .all : 0 } }; } \
-	_Ostream_Manip(T) wd( unsigned char w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, CODE, { .all : 0 } }; } \
-	_Ostream_Manip(T) wd( unsigned char w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \
-	_Ostream_Manip(T) & wd( unsigned char w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
-	_Ostream_Manip(T) & wd( unsigned char w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
+	_Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, CODE, { .all : 0 } }; } \
+	_Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \
+	_Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
+	_Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
 	_Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
 	_Ostream_Manip(T) & upcase( _Ostream_Manip(T) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; } \
@@ -190,5 +190,5 @@
 	_Ostream_Manip(T) sign( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, CODE, { .flags.sign : true } }; } \
 	_Ostream_Manip(T) & sign( _Ostream_Manip(T) & fmt ) { fmt.flags.sign = true; return fmt; } \
-} \
+} /* distribution */ \
 forall( dtype ostype | ostream( ostype ) ) { \
 	ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
@@ -214,9 +214,9 @@
 	_Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \
 	_Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \
-	_Ostream_Manip(T) wd( unsigned char w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \
-	_Ostream_Manip(T) wd( unsigned char w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
-	_Ostream_Manip(T) ws( unsigned char w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
-	_Ostream_Manip(T) & wd( unsigned char w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
-	_Ostream_Manip(T) & wd( unsigned char w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
+	_Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \
+	_Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
+	_Ostream_Manip(T) ws( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
+	_Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
+	_Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
 	_Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
 	_Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'G', { .all : 0 } }; } \
@@ -227,5 +227,5 @@
 	_Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
 	_Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
-} \
+} /* distribution */ \
 forall( dtype ostype | ostream( ostype ) ) { \
 	ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
@@ -239,9 +239,9 @@
 
 static inline {
-	_Ostream_Manip(char) bin( char val ) { return (_Ostream_Manip(char))@{ val, 1, 0, 'b', { .all : 0 } }; }
-	_Ostream_Manip(char) oct( char val ) { return (_Ostream_Manip(char))@{ val, 1, 0, 'o', { .all : 0 } }; }
-	_Ostream_Manip(char) hex( char val ) { return (_Ostream_Manip(char))@{ val, 1, 0, 'x', { .all : 0 } }; }
-	_Ostream_Manip(char) wd( unsigned char w, char val ) { return (_Ostream_Manip(char))@{ val, w, 0, 'c', { .all : 0 } }; }
-	_Ostream_Manip(char) & wd( unsigned char w, _Ostream_Manip(char) & fmt ) { fmt.wd = w; return fmt; }
+	_Ostream_Manip(char) bin( char c ) { return (_Ostream_Manip(char))@{ c, 1, 0, 'b', { .all : 0 } }; }
+	_Ostream_Manip(char) oct( char c ) { return (_Ostream_Manip(char))@{ c, 1, 0, 'o', { .all : 0 } }; }
+	_Ostream_Manip(char) hex( char c ) { return (_Ostream_Manip(char))@{ c, 1, 0, 'x', { .all : 0 } }; }
+	_Ostream_Manip(char) wd( unsigned int w, char c ) { return (_Ostream_Manip(char))@{ c, w, 0, 'c', { .all : 0 } }; }
+	_Ostream_Manip(char) & wd( unsigned int w, _Ostream_Manip(char) & fmt ) { fmt.wd = w; return fmt; }
 	_Ostream_Manip(char) & left( _Ostream_Manip(char) & fmt ) { fmt.flags.left = true; return fmt; }
 	_Ostream_Manip(char) & upcase( _Ostream_Manip(char) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; }
@@ -256,11 +256,11 @@
 
 static inline {
-	_Ostream_Manip(const char *) bin( const char * val ) { return (_Ostream_Manip(const char *))@{ val, 1, 0, 'b', { .all : 0 } }; }
-	_Ostream_Manip(const char *) oct( const char * val ) { return (_Ostream_Manip(const char *))@{ val, 1, 0, 'o', { .all : 0 } }; }
-	_Ostream_Manip(const char *) hex( const char * val ) { return (_Ostream_Manip(const char *))@{ val, 1, 0, 'x', { .all : 0 } }; }
-	_Ostream_Manip(const char *) wd( unsigned char w, const char * val ) { return (_Ostream_Manip(const char *))@{ val, w, 0, 's', { .all : 0 } }; }
-	_Ostream_Manip(const char *) wd( unsigned char w, unsigned char pc, const char * val ) { return (_Ostream_Manip(const char *))@{ val, w, pc, 's', { .flags.pc : true } }; }
-	_Ostream_Manip(const char *) & wd( unsigned char w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
-	_Ostream_Manip(const char *) & wd( unsigned char w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
+	_Ostream_Manip(const char *) bin( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; }
+	_Ostream_Manip(const char *) oct( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; }
+	_Ostream_Manip(const char *) hex( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
+	_Ostream_Manip(const char *) wd( unsigned int w, const char * s ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
+	_Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char * s ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
+	_Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
+	_Ostream_Manip(const char *) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
 	_Ostream_Manip(const char *) & left( _Ostream_Manip(const char *) & fmt ) { fmt.flags.left = true; return fmt; }
 	_Ostream_Manip(const char *) & nobase( _Ostream_Manip(const char *) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
@@ -316,6 +316,6 @@
 	istype & ?|?( istype &, long double _Complex & );
 
-	// Cannot have char & and char * => cstr manipulator
-	// istype & ?|?( istype &, char * );
+	istype & ?|?( istype &, const char * );
+	istype & ?|?( istype &, char * );
 
 	// manipulators
@@ -341,15 +341,27 @@
 }; // _Istream_Cstr
 
-static inline _Istream_Cstr skip( const char * scanset ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
-static inline _Istream_Cstr incl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
-static inline _Istream_Cstr incl( const char * scanset, _Istream_Cstr & fmt ) { fmt.flags.inex = false; return fmt; }
-static inline _Istream_Cstr excl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
-static inline _Istream_Cstr excl( const char * scanset, _Istream_Cstr & fmt ) { fmt.flags.inex = true; return fmt; }
-static inline _Istream_Cstr cstr( char * s ) { return (_Istream_Cstr){ s, 0p, -1, { .all : 0 } }; }
-static inline _Istream_Cstr ignore( const char * s ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
-static inline _Istream_Cstr ignore( _Istream_Cstr & fmt ) { fmt.flags.ignore = true; return fmt; }
-static inline _Istream_Cstr wd( unsigned int w, char * s ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
-static inline _Istream_Cstr wd( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
-forall( dtype istype | istream( istype ) ) istype & ?|?( istype &, _Istream_Cstr );
+static inline {
+	_Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }
+	_Istream_Cstr skip( const char * scanset ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
+	_Istream_Cstr incl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
+	_Istream_Cstr & incl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
+	_Istream_Cstr excl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
+	_Istream_Cstr & excl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
+	_Istream_Cstr ignore( const char * s ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
+	_Istream_Cstr & ignore( _Istream_Cstr & fmt ) { fmt.flags.ignore = true; return fmt; }
+	_Istream_Cstr wd( unsigned int w, char * s ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
+	_Istream_Cstr & wd( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
+} // distribution
+forall( dtype istype | istream( istype ) ) istype & ?|?( istype & is, _Istream_Cstr f );
+
+struct _Istream_Char {
+	bool ignore;										// do not change input argument
+}; // _Istream_Char
+
+static inline {
+	_Istream_Char ignore( const char c ) { return (_Istream_Char)@{ true }; }
+	_Istream_Char & ignore( _Istream_Char & fmt ) { fmt.ignore = true; return fmt; }
+} // distribution
+forall( dtype istype | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f );
 
 forall( otype T )
@@ -361,12 +373,14 @@
 
 #define InputFMTDecl( T ) \
-static inline _Istream_Manip(T) ignore( const T & val ) { return (_Istream_Manip(T))@{ (T &)val, -1, true }; } \
-static inline _Istream_Manip(T) ignore( _Istream_Manip(T) & fmt ) { fmt.ignore = true; return fmt; } \
-static inline _Istream_Manip(T) wd( unsigned int w, T & val ) { return (_Istream_Manip(T))@{ val, w, false }; } \
+static inline { \
+	_Istream_Manip(T) ignore( const T & val ) { return (_Istream_Manip(T))@{ (T &)val, -1, true }; } \
+	_Istream_Manip(T) & ignore( _Istream_Manip(T) & fmt ) { fmt.ignore = true; return fmt; } \
+	_Istream_Manip(T) wdi( unsigned int w, T & val ) { return (_Istream_Manip(T))@{ val, w, false }; } \
+	_Istream_Manip(T) & wd( unsigned int w, _Istream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
+} /* distribution */ \
 forall( dtype istype | istream( istype ) ) { \
 	istype & ?|?( istype & is, _Istream_Manip(T) f ); \
 } // ?|?
 
-InputFMTDecl( char )
 InputFMTDecl( signed char )
 InputFMTDecl( unsigned char )
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/AST/Convert.cpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -2193,6 +2193,12 @@
 
 	int isStringlikeConstantType(const Type *t) {
+		const Type *referentType = nullptr;
 		if ( const ArrayType * aty = dynamic_cast< const ArrayType * >( t ) ) {
-			if ( const BasicType * bty = dynamic_cast< const BasicType * >( aty->base ) ) {
+			referentType = aty->base;
+		} else if ( const PointerType * pty = dynamic_cast< const PointerType * >( t ) ) {
+			referentType = pty->base;
+		}
+		if (referentType) {
+			if ( const BasicType * bty = dynamic_cast< const BasicType * >( referentType ) ) {
 			   if ( bty->kind == BasicType::Kind::Char ) {
 				   return true;
@@ -2205,5 +2211,13 @@
 	virtual void visit( ConstantExpr * old ) override final {
 		ast::ConstantExpr *rslt = nullptr;
-		if (isIntlikeConstantType(old->result)) {
+		if (isStringlikeConstantType(old->result)) {
+			rslt = new ast::ConstantExpr(
+				old->location,
+				GET_ACCEPT_1(result, Type),
+				old->constant.get_value(),
+				0,
+				ast::ConstantExpr::Kind::String
+			);
+		} else if (isIntlikeConstantType(old->result)) {
 			rslt = new ast::ConstantExpr(
 				old->location,
@@ -2219,12 +2233,4 @@
 				old->constant.get_value(),
 				(double) old->constant.get_dval()
-			);
-		} else if (isStringlikeConstantType(old->result)) {
-			rslt = new ast::ConstantExpr(
-				old->location,
-				GET_ACCEPT_1(result, Type),
-				old->constant.get_value(),
-				0,
-				ast::ConstantExpr::Kind::String
 			);
 		}
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/AST/Node.hpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -99,14 +99,26 @@
 
 /// Mutate a node field (only clones if not equal to existing value)
-template<typename node_t, typename field_t>
-const node_t * mutate_field( 
-	const node_t * node, 
-	typename std::remove_const<typename std::remove_reference<field_t>::type>::type node_t::* field,
-	field_t&& val 
-) {
+template<typename node_t, typename field_t, typename assn_t>
+const node_t * mutate_field( const node_t * node, field_t node_t::* field, assn_t && val ) {
+	// skip mutate if equivalent
 	if ( node->*field == val ) return node;
 	
+	// mutate and return
 	node_t * ret = mutate( node );
-	ret->*field = std::forward< field_t >( val );
+	ret->*field = std::forward< assn_t >( val );
+	return ret;
+}
+
+/// Mutate a single index of a node field (only clones if not equal to existing value)
+template<typename node_t, typename coll_t, typename ind_t, typename field_t>
+const node_t * mutate_field_index(
+	const node_t * node, coll_t node_t::* field, ind_t i, field_t && val
+) {
+	// skip mutate if equivalent
+	if  ( (node->*field)[i] == val ) return node;
+
+	// mutate and return
+	node_t * ret = mutate( node );
+	(ret->*field)[i] = std::forward< field_t >( val );
 	return ret;
 }
Index: src/AST/Print.hpp
===================================================================
--- src/AST/Print.hpp	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/AST/Print.hpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -16,6 +16,6 @@
 #pragma once
 
-#include <iosfwd>
-#include <utility> // for forward
+#include <iostream>
+#include <utility>   // for forward
 
 #include "AST/Node.hpp"
@@ -32,6 +32,14 @@
 void printShort( std::ostream & os, const ast::Decl * node, Indenter indent = {} );
 
-inline void printShort( std::ostream & os, const ast::Decl * node, unsigned int indent ) {
-    printShort( os, node, Indenter{ indent } );
+/// Print a collection of items
+template< typename Coll >
+void printAll( std::ostream & os, const Coll & c, Indenter indent = {} ) {
+    for ( const auto & i : c ) {
+        if ( ! i ) continue;
+        
+        os << indent;
+        print( os, i, indent );
+        os << std::endl;
+    }
 }
 
Index: src/AST/porting.md
===================================================================
--- src/AST/porting.md	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/AST/porting.md	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -299,4 +299,7 @@
 * `openVars` => `open`
 
+`ExplodedActual` => `ExplodedArg`
+* `ExplodedActual.h` => `ExplodedArg.hpp`
+
 [1] https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/Type-Attributes.html#Type-Attributes
 
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/InitTweak/InitTweak.cc	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -1,2 +1,17 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// InitTweak.cc --
+//
+// Author           : Rob Schluntz
+// Created On       : Fri May 13 11:26:36 2016
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 10 13:30:00 2019
+// Update Count     : 5
+//
+
 #include <algorithm>               // for find, all_of
 #include <cassert>                 // for assertf, assert, strict_dynamic_cast
@@ -4,4 +19,5 @@
 #include <iterator>                // for back_insert_iterator, back_inserter
 #include <memory>                  // for __shared_ptr
+#include <vector>
 
 #include "AST/Expr.hpp"
@@ -307,6 +323,6 @@
 	}
 
-	struct CallFinder {
-		CallFinder( const std::list< std::string > & names ) : names( names ) {}
+	struct CallFinder_old {
+		CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
 
 		void postvisit( ApplicationExpr * appExpr ) {
@@ -331,8 +347,31 @@
 	};
 
+	struct CallFinder_new final {
+		std::vector< ast::ptr< ast::Expr > > matches;
+		const std::vector< std::string > names;
+
+		CallFinder_new( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}
+
+		void handleCallExpr( const ast::Expr * expr ) {
+			std::string fname = getFunctionName( expr );
+			if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
+				matches.emplace_back( expr );
+			}
+		}
+
+		void postvisit( const ast::ApplicationExpr * expr ) { handleCallExpr( expr ); }
+		void postvisit( const ast::UntypedExpr *     expr ) { handleCallExpr( expr ); }
+	};
+
 	void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {
-		static PassVisitor<CallFinder> finder( std::list< std::string >{ "?{}", "^?{}" } );
+		static PassVisitor<CallFinder_old> finder( std::list< std::string >{ "?{}", "^?{}" } );
 		finder.pass.matches = &matches;
 		maybeAccept( stmt, finder );
+	}
+
+	std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt ) {
+		ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
+		maybe_accept( stmt, finder );
+		return std::move( finder.pass.matches );
 	}
 
@@ -436,4 +475,18 @@
 	}
 
+	const ast::ApplicationExpr * isIntrinsicCallExpr( const ast::Expr * expr ) {
+		auto appExpr = dynamic_cast< const ast::ApplicationExpr * >( expr );
+		if ( ! appExpr ) return nullptr;
+
+		const ast::DeclWithType * func = getCalledFunction( appExpr->func );
+		assertf( func, 
+			"getCalledFunction returned nullptr: %s", toString( appExpr->func ).c_str() );
+		
+		// check for Intrinsic only -- don't want to remove all overridable ctor/dtor because 
+		// autogenerated ctor/dtor will call all member dtors, and some members may have a 
+		// user-defined dtor
+		return func->linkage == ast::Linkage::Intrinsic ? appExpr : nullptr;
+	}
+
 	namespace {
 		template <typename Predicate>
@@ -444,4 +497,10 @@
 			return std::all_of( callExprs.begin(), callExprs.end(), pred);
 		}
+
+		template <typename Predicate>
+		bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
+			std::vector< ast::ptr< ast::Expr > > callExprs = collectCtorDtorCalls( stmt );
+			return std::all_of( callExprs.begin(), callExprs.end(), pred );
+		}
 	}
 
@@ -452,4 +511,16 @@
 				assert( funcType );
 				return funcType->get_parameters().size() == 1;
+			}
+			return false;
+		});
+	}
+
+	bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) {
+		return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){
+			if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
+				const ast::FunctionType * funcType = 
+					GenPoly::getFunctionType( appExpr->func->result );
+				assert( funcType );
+				return funcType->params.size() == 1;
 			}
 			return false;
Index: src/InitTweak/InitTweak.h
===================================================================
--- src/InitTweak/InitTweak.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/InitTweak/InitTweak.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -5,11 +5,11 @@
 // file "LICENCE" distributed with Cforall.
 //
-// RemoveInit.h --
+// InitTweak.h --
 //
 // Author           : Rob Schluntz
 // Created On       : Fri May 13 11:26:36 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:30:33 2017
-// Update Count     : 4
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 10 13:30:00 2019
+// Update Count     : 5
 //
 
@@ -19,4 +19,5 @@
 #include <memory>             // for shared_ptr
 #include <string>             // for string, allocator
+#include <vector>
 
 #include "AST/Fwd.hpp"        // for AST nodes
@@ -63,4 +64,5 @@
 	/// Non-Null if expr is a call expression whose target function is intrinsic
 	ApplicationExpr * isIntrinsicCallExpr( Expression * expr );
+	const ast::ApplicationExpr * isIntrinsicCallExpr( const ast::Expr * expr);
 
 	/// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
@@ -68,4 +70,5 @@
 	/// Currently has assertions that make it less than fully general.
 	bool isIntrinsicSingleArgCallStmt( Statement * stmt );
+	bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
 
 	/// True if stmt is a call statement where the function called is intrinsic.
@@ -74,4 +77,5 @@
 	/// get all Ctor/Dtor call expressions from a Statement
 	void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
+	std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt );
 
 	/// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/Makefile.in	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -195,4 +195,5 @@
 	ResolvExpr/CurrentObject.$(OBJEXT) \
 	ResolvExpr/ExplodedActual.$(OBJEXT) \
+	ResolvExpr/ExplodedArg.$(OBJEXT) \
 	ResolvExpr/FindOpenVars.$(OBJEXT) ResolvExpr/Occurs.$(OBJEXT) \
 	ResolvExpr/PolyCost.$(OBJEXT) \
@@ -203,4 +204,5 @@
 	ResolvExpr/Resolver.$(OBJEXT) \
 	ResolvExpr/ResolveTypeof.$(OBJEXT) \
+	ResolvExpr/SatisfyAssertions.$(OBJEXT) \
 	ResolvExpr/SpecCost.$(OBJEXT) \
 	ResolvExpr/TypeEnvironment.$(OBJEXT) \
@@ -632,4 +634,5 @@
       ResolvExpr/CurrentObject.cc \
       ResolvExpr/ExplodedActual.cc \
+      ResolvExpr/ExplodedArg.cpp \
       ResolvExpr/FindOpenVars.cc \
       ResolvExpr/Occurs.cc \
@@ -641,4 +644,5 @@
       ResolvExpr/Resolver.cc \
       ResolvExpr/ResolveTypeof.cc \
+      ResolvExpr/SatisfyAssertions.cpp \
       ResolvExpr/SpecCost.cc \
       ResolvExpr/TypeEnvironment.cc \
@@ -893,4 +897,6 @@
 ResolvExpr/ExplodedActual.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
 	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
+ResolvExpr/ExplodedArg.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
+	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
 ResolvExpr/FindOpenVars.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
 	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
@@ -910,4 +916,6 @@
 	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
 ResolvExpr/ResolveTypeof.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
+	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
+ResolvExpr/SatisfyAssertions.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
 	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
 ResolvExpr/SpecCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
@@ -1273,4 +1281,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/CurrentObject.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/ExplodedActual.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/ExplodedArg.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/FindOpenVars.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/Occurs.Po@am__quote@
@@ -1282,4 +1291,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/ResolveTypeof.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/Resolver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/SatisfyAssertions.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/SpecCost.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/TypeEnvironment.Po@am__quote@
Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/AdjustExprType.cc	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// AdjustExprType.cc --
+// AdjustExprType_old.cc --
 //
 // Author           : Richard C. Bilson
@@ -14,4 +14,9 @@
 //
 
+#include "AST/Node.hpp"
+#include "AST/Pass.hpp"
+#include "AST/SymbolTable.hpp"
+#include "AST/Type.hpp"
+#include "AST/TypeEnvironment.hpp"
 #include "Common/PassVisitor.h"
 #include "SymTab/Indexer.h"       // for Indexer
@@ -22,7 +27,9 @@
 
 namespace ResolvExpr {
-	class AdjustExprType : public WithShortCircuiting {
-	  public:
-		AdjustExprType( const TypeEnvironment & env, const SymTab::Indexer & indexer );
+
+namespace {
+	class AdjustExprType_old final : public WithShortCircuiting {
+		public:
+		AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer );
 		void premutate( VoidType * ) { visit_children = false; }
 		void premutate( BasicType * ) { visit_children = false; }
@@ -44,26 +51,14 @@
 		Type * postmutate( TypeInstType *aggregateUseType );
 
-	  private:
+		private:
 		const TypeEnvironment & env;
 		const SymTab::Indexer & indexer;
 	};
 
-	void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
-		PassVisitor<AdjustExprType> adjuster( env, indexer );
-		Type *newType = type->acceptMutator( adjuster );
-		type = newType;
-	}
-
-	void adjustExprType( Type *& type ) {
-		TypeEnvironment env;
-		SymTab::Indexer indexer;
-		adjustExprType( type, env, indexer );
-	}
-
-	AdjustExprType::AdjustExprType( const TypeEnvironment &env, const SymTab::Indexer &indexer )
+	AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer )
 		: env( env ), indexer( indexer ) {
 	}
 
-	Type * AdjustExprType::postmutate( ArrayType * arrayType ) {
+	Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) {
 		PointerType *pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base };
 		arrayType->base = nullptr;
@@ -72,9 +67,9 @@
 	}
 
-	Type * AdjustExprType::postmutate( FunctionType * functionType ) {
+	Type * AdjustExprType_old::postmutate( FunctionType * functionType ) {
 		return new PointerType{ Type::Qualifiers(), functionType };
 	}
 
-	Type * AdjustExprType::postmutate( TypeInstType * typeInst ) {
+	Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) {
 		if ( const EqvClass* eqvClass = env.lookup( typeInst->get_name() ) ) {
 			if ( eqvClass->data.kind == TypeDecl::Ftype ) {
@@ -90,4 +85,74 @@
 		return typeInst;
 	}
+} // anonymous namespace
+
+void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
+	PassVisitor<AdjustExprType_old> adjuster( env, indexer );
+	Type *newType = type->acceptMutator( adjuster );
+	type = newType;
+}
+
+void adjustExprType( Type *& type ) {
+	TypeEnvironment env;
+	SymTab::Indexer indexer;
+	adjustExprType( type, env, indexer );
+}
+
+namespace {
+	struct AdjustExprType_new final : public ast::WithShortCircuiting {
+		const ast::TypeEnvironment & tenv;
+		const ast::SymbolTable & symtab;
+
+		AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
+		: tenv( e ), symtab( syms ) {}
+
+		void premutate( const ast::VoidType * ) { visit_children = false; }
+		void premutate( const ast::BasicType * ) { visit_children = false; }
+		void premutate( const ast::PointerType * ) { visit_children = false; }
+		void premutate( const ast::ArrayType * ) { visit_children = false; }
+		void premutate( const ast::FunctionType * ) { visit_children = false; }
+		void premutate( const ast::StructInstType * ) { visit_children = false; }
+		void premutate( const ast::UnionInstType * ) { visit_children = false; }
+		void premutate( const ast::EnumInstType * ) { visit_children = false; }
+		void premutate( const ast::TraitInstType * ) { visit_children = false; }
+		void premutate( const ast::TypeInstType * ) { visit_children = false; }
+		void premutate( const ast::TupleType * ) { visit_children = false; }
+		void premutate( const ast::VarArgsType * ) { visit_children = false; }
+		void premutate( const ast::ZeroType * ) { visit_children = false; }
+		void premutate( const ast::OneType * ) { visit_children = false; }
+
+		const ast::Type * postmutate( const ast::ArrayType * at ) {
+			return new ast::PointerType{ at->base, at->qualifiers };
+		}
+
+		const ast::Type * postmutate( const ast::FunctionType * ft ) {
+			return new ast::PointerType{ ft };
+		}
+
+		const ast::Type * postmutate( const ast::TypeInstType * inst ) {
+			// replace known function-type-variables with pointer-to-function
+			if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
+				if ( eqvClass->data.kind == ast::TypeVar::Ftype ) {
+					return new ast::PointerType{ inst };
+				}
+			} else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) {
+				if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) {
+					if ( tyDecl->kind == ast::TypeVar::Ftype ) {
+						return new ast::PointerType{ inst };
+					}
+				}
+			}
+			return inst;
+		}
+	};
+} // anonymous namespace
+
+const ast::Type * adjustExprType( 
+	const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab 
+) {
+	ast::Pass<AdjustExprType_new> adjuster{ env, symtab };
+	return type->accept( adjuster );
+}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -29,4 +29,5 @@
 #include "AlternativeFinder.h"
 #include "AST/Expr.hpp"
+#include "AST/SymbolTable.hpp"
 #include "AST/Type.hpp"
 #include "Common/SemanticError.h"  // for SemanticError
@@ -115,5 +116,5 @@
 		/// Finds matching alternatives for a function, given a set of arguments
 		template<typename OutputIterator>
-		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
+		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs_old& args, OutputIterator out );
 		/// Sets up parameter inference for an output alternative
 		template< typename OutputIterator >
@@ -266,5 +267,5 @@
 			SemanticError( expr, "No reasonable alternatives for expression " );
 		}
-		if ( mode.resolveAssns || mode.prune ) {
+		if ( mode.satisfyAssns || mode.prune ) {
 			// trim candidates just to those where the assertions resolve
 			// - necessary pre-requisite to pruning
@@ -592,5 +593,5 @@
 
 		/// Gets the list of exploded alternatives for this pack
-		const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
+		const ExplodedActual& getExpl( const ExplodedArgs_old& args ) const {
 			return args[nextArg-1][explAlt];
 		}
@@ -616,5 +617,5 @@
 	/// Instantiates an argument to match a formal, returns false if no results left
 	bool instantiateArgument( Type* formalType, Initializer* initializer,
-			const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
+			const ExplodedArgs_old& args, std::vector<ArgPack>& results, std::size_t& genStart,
 			const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
 		if ( TupleType * tupleType = dynamic_cast<TupleType*>( formalType ) ) {
@@ -888,5 +889,5 @@
 	template<typename OutputIterator>
 	void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
-			FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
+			FunctionType *funcType, const ExplodedArgs_old &args, OutputIterator out ) {
 		OpenVarSet funcOpenVars;
 		AssertionSet funcNeed, funcHave;
@@ -1020,5 +1021,5 @@
 
 		// pre-explode arguments
-		ExplodedArgs argExpansions;
+		ExplodedArgs_old argExpansions;
 		argExpansions.reserve( argAlternatives.size() );
 
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/AlternativeFinder.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -37,5 +37,5 @@
 	/// First index is which argument, second index is which alternative for that argument,
 	/// third index is which exploded element of that alternative
-	using ExplodedArgs = std::vector< std::vector< ExplodedActual > >;
+	using ExplodedArgs_old = std::vector< std::vector< ExplodedActual > >;
 
 	class AlternativeFinder {
Index: src/ResolvExpr/Candidate.hpp
===================================================================
--- src/ResolvExpr/Candidate.hpp	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/Candidate.hpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -30,4 +30,9 @@
 	/// A list of unresolved assertions
 	using AssertionList = std::vector<AssertionSet::value_type>;
+
+	/// Convenience to merge AssertionList into AssertionSet
+	static inline void mergeAssertionSet( AssertionSet & dst, const AssertionList & src ) {
+		for ( const auto & s : src ) { dst.emplace( s ); }
+	}
 }
 
@@ -42,4 +47,19 @@
 	ast::OpenVarSet open;      ///< Open variables for environment
 	ast::AssertionList need;   ///< Assertions which need to be resolved
+
+	Candidate() : expr(), cost( Cost::zero ), cvtCost( Cost::zero ), env(), open(), need() {}
+	
+	Candidate( const ast::Expr * x, const ast::TypeEnvironment & e )
+	: 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 ), 
+	  need( o.need ) {}
+	
+	Candidate( 
+		const ast::Expr * x, ast::TypeEnvironment && e, ast::OpenVarSet && o, 
+		ast::AssertionSet && n, const Cost & c )
+	: expr( x ), cost( c ), cvtCost( Cost::zero ), env( std::move( e ) ), open( std::move( o ) ), 
+	  need( n.begin(), n.end() ) {}
 };
 
@@ -49,4 +69,31 @@
 /// List of candidates
 using CandidateList = std::vector< CandidateRef >;
+
+/// Splice src after dst, clearing src
+static inline void splice( CandidateList & dst, CandidateList & src ) {
+	dst.reserve( dst.size() + src.size() );
+	for ( CandidateRef & r : src ) { dst.emplace_back( std::move( r ) ); }
+	src.clear();
+}
+
+/// Splice src before dst
+static inline void spliceBegin( CandidateList & dst, CandidateList & src ) {
+	splice( src, dst );
+	dst.swap( src );
+}
+
+/// Sum the cost of a list of candidates
+static inline Cost sumCost( const CandidateList & candidates ) {
+	Cost total = Cost::zero;
+	for ( const CandidateRef & r : candidates ) { total += r->cost; }
+	return total;
+}
+
+/// Holdover behaviour from old `findMinCost` -- xxx -- can maybe be eliminated?
+static inline void promoteCvtCost( CandidateList & candidates ) {
+	for ( CandidateRef & r : candidates ) {
+		r->cost = r->cvtCost;
+	}
+}
 
 void print( std::ostream & os, const Candidate & cand, Indenter indent = {} );
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -16,12 +16,723 @@
 #include "CandidateFinder.hpp"
 
+#include <deque>
+#include <iterator>               // for back_inserter
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "Candidate.hpp"
+#include "CompilationState.h"
+#include "Cost.h"
+#include "ExplodedArg.hpp"
+#include "Resolver.h"
+#include "SatisfyAssertions.hpp"
+#include "typeops.h"              // for adjustExprType
+#include "Unify.h"
 #include "AST/Expr.hpp"
+#include "AST/Node.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Print.hpp"
+#include "AST/SymbolTable.hpp"
+#include "AST/Type.hpp"
+#include "SymTab/Mangler.h"
+#include "Tuples/Tuples.h"        // for handleTupleAssignment
+
+#define PRINT( text ) if ( resolvep ) { text }
 
 namespace ResolvExpr {
 
+namespace {
+
+	/// First index is which argument, second is which alternative, third is which exploded element
+	using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
+
+	/// Returns a list of alternatives with the minimum cost in the given list
+	CandidateList findMinCost( const CandidateList & candidates ) {
+		CandidateList out;
+		Cost minCost = Cost::infinity;
+		for ( const CandidateRef & r : candidates ) {
+			if ( r->cost < minCost ) {
+				minCost = r->cost;
+				out.clear();
+				out.emplace_back( r );
+			} else if ( r->cost == minCost ) {
+				out.emplace_back( r );
+			}
+		}
+		return out;
+	}
+
+	/// Computes conversion cost for a given candidate
+	Cost computeApplicationConversionCost( 
+		const CandidateRef & cand, const ast::SymbolTable & symtab 
+	) {
+		#warning unimplemented
+		(void)cand; (void)symtab;
+		assert(false);
+		return Cost::infinity;
+	}
+
+	/// Actually visits expressions to find their candidate interpretations
+	struct Finder final : public ast::WithShortCircuiting {
+		CandidateFinder & selfFinder;
+		const ast::SymbolTable & symtab;
+		CandidateList & candidates;
+		const ast::TypeEnvironment & tenv;
+		ast::ptr< ast::Type > & targetType;
+
+		Finder( CandidateFinder & f )
+		: selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ), 
+		  targetType( f.targetType ) {}
+		
+		void previsit( const ast::Node * ) { visit_children = false; }
+
+		/// Convenience to add candidate to list
+		template<typename... Args>
+		void addCandidate( Args &&... args ) {
+			candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
+		}
+
+		void postvisit( const ast::ApplicationExpr * applicationExpr ) {
+			addCandidate( applicationExpr, tenv );
+		}
+
+		/// Builds a list of candidates for a function, storing them in out
+		void makeFunctionCandidates(
+			const CandidateRef & func, const ast::FunctionType * funcType, 
+			const ExplodedArgs_new & args, CandidateList & out
+		) {
+			#warning unimplemented
+			(void)func; (void)funcType; (void)args; (void)out;
+			assert(false);
+		}
+
+		/// Adds implicit struct-conversions to the alternative list
+		void addAnonConversions( const CandidateRef & cand ) {
+			#warning unimplemented
+			(void)cand;
+			assert(false);
+		}
+
+		void postvisit( const ast::UntypedExpr * untypedExpr ) {
+			CandidateFinder funcFinder{ symtab, tenv };
+			funcFinder.find( untypedExpr->func, ResolvMode::withAdjustment() );
+			// short-circuit if no candidates
+			if ( funcFinder.candidates.empty() ) return;
+
+			std::vector< CandidateFinder > argCandidates = 
+				selfFinder.findSubExprs( untypedExpr->args );
+			
+			// take care of possible tuple assignments
+			// if not tuple assignment, handled as normal function call
+			Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
+
+			// find function operators
+			ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" };
+			CandidateFinder opFinder{ symtab, tenv };
+			// okay if there aren't any function operations
+			opFinder.find( opExpr, ResolvMode::withoutFailFast() );
+			PRINT(
+				std::cerr << "known function ops:" << std::endl;
+				print( std::cerr, opFinder.candidates, 1 );
+			)
+
+			// pre-explode arguments
+			ExplodedArgs_new argExpansions;
+			for ( const CandidateFinder & args : argCandidates ) {
+				argExpansions.emplace_back();
+				auto & argE = argExpansions.back();
+				for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
+			}
+
+			// Find function matches
+			CandidateList found;
+			SemanticErrorException errors;
+			for ( CandidateRef & func : funcFinder ) {
+				try {
+					PRINT(
+						std::cerr << "working on alternative:" << std::endl;
+						print( std::cerr, *func, 2 );
+					)
+
+					// check if the type is a pointer to function
+					const ast::Type * funcResult = func->expr->result->stripReferences();
+					if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
+						if ( auto function = pointer->base.as< ast::FunctionType >() ) {
+							CandidateRef newFunc{ new Candidate{ *func } };
+							newFunc->expr = 
+								referenceToRvalueConversion( newFunc->expr, newFunc->cost );
+							makeFunctionCandidates( newFunc, function, argExpansions, found );
+						}
+					} else if ( 
+						auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 
+					) {
+						if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
+							if ( auto function = clz->bound.as< ast::FunctionType >() ) {
+								CandidateRef newFunc{ new Candidate{ *func } };
+								newFunc->expr = 
+									referenceToRvalueConversion( newFunc->expr, newFunc->cost );
+								makeFunctionCandidates( newFunc, function, argExpansions, found );
+							}
+						}
+					}
+				} catch ( SemanticErrorException & e ) { errors.append( e ); }
+			}
+
+			// Find matches on function operators `?()`
+			if ( ! opFinder.candidates.empty() ) {
+				// add exploded function alternatives to front of argument list
+				std::vector< ExplodedArg > funcE;
+				funcE.reserve( funcFinder.candidates.size() );
+				for ( const CandidateRef & func : funcFinder ) { 
+					funcE.emplace_back( *func, symtab );
+				}
+				argExpansions.emplace_front( std::move( funcE ) );
+
+				for ( const CandidateRef & op : opFinder ) {
+					try {
+						// check if type is pointer-to-function
+						const ast::Type * opResult = op->expr->result->stripReferences();
+						if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
+							if ( auto function = pointer->base.as< ast::FunctionType >() ) {
+								CandidateRef newOp{ new Candidate{ *op} };
+								newOp->expr = 
+									referenceToRvalueConversion( newOp->expr, newOp->cost );
+								makeFunctionCandidates( newOp, function, argExpansions, found );
+							}
+						}
+					} catch ( SemanticErrorException & e ) { errors.append( e ); }
+				}
+			}
+
+			// Implement SFINAE; resolution errors are only errors if there aren't any non-error 
+			// candidates
+			if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
+
+			// Compute conversion costs
+			for ( CandidateRef & withFunc : found ) {
+				Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
+
+				PRINT(
+					auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
+					auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
+					auto function = pointer->base.strict_as< ast::FunctionType >();
+					
+					std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
+					std::cerr << "parameters are:" << std::endl;
+					ast::printAll( std::cerr, function->params, 2 );
+					std::cerr << "arguments are:" << std::endl;
+					ast::printAll( std::cerr, appExpr->args, 2 );
+					std::cerr << "bindings are:" << std::endl;
+					ast::print( std::cerr, withFunc->env, 2 );
+					std::cerr << "cost is: " << withFunc->cost << std::endl;
+					std::cerr << "cost of conversion is:" << cvtCost << std::endl;
+				)
+
+				if ( cvtCost != Cost::infinity ) {
+					withFunc->cvtCost = cvtCost;
+					candidates.emplace_back( std::move( withFunc ) );
+				}
+			}
+			found = std::move( candidates );
+
+			// use a new list so that candidates are not examined by addAnonConversions twice
+			CandidateList winners = findMinCost( found );
+			promoteCvtCost( winners );
+
+			// function may return a struct/union value, in which case we need to add candidates 
+			// for implicit conversions to each of the anonymous members, which must happen after 
+			// `findMinCost`, since anon conversions are never the cheapest
+			for ( const CandidateRef & c : winners ) {
+				addAnonConversions( c );
+			}
+			spliceBegin( candidates, winners );
+
+			if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
+				// If resolution is unsuccessful with a target type, try again without, since it 
+				// will sometimes succeed when it wouldn't with a target type binding.
+				// For example:
+				//   forall( otype T ) T & ?[]( T *, ptrdiff_t );
+				//   const char * x = "hello world";
+				//   unsigned char ch = x[0];
+				// Fails with simple return type binding (xxx -- check this!) as follows:
+				// * T is bound to unsigned char
+				// * (x: const char *) is unified with unsigned char *, which fails
+				// xxx -- fix this better
+				targetType = nullptr;
+				postvisit( untypedExpr );
+			}
+		}
+
+		/// true if expression is an lvalue
+		static bool isLvalue( const ast::Expr * x ) {
+			return x->result && ( x->result->is_lvalue() || x->result.as< ast::ReferenceType >() );
+		}
+
+		void postvisit( const ast::AddressExpr * addressExpr ) {
+			CandidateFinder finder{ symtab, tenv };
+			finder.find( addressExpr->arg );
+			for ( CandidateRef & r : finder.candidates ) {
+				if ( ! isLvalue( r->expr ) ) continue;
+				addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
+			}
+		}
+
+		void postvisit( const ast::LabelAddressExpr * labelExpr ) {
+			addCandidate( labelExpr, tenv );
+		}
+
+		void postvisit( const ast::CastExpr * castExpr ) {
+			#warning unimplemented
+			(void)castExpr;
+			assert(false);
+		}
+
+		void postvisit( const ast::VirtualCastExpr * castExpr ) {
+			assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
+			CandidateFinder finder{ symtab, tenv };
+			// don't prune here, all alternatives guaranteed to have same type
+			finder.find( castExpr->arg, ResolvMode::withoutPrune() );
+			for ( CandidateRef & r : finder.candidates ) {
+				addCandidate( 
+					*r, new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
+			}
+		}
+
+		void postvisit( const ast::UntypedMemberExpr * memberExpr ) {
+			#warning unimplemented
+			(void)memberExpr;
+			assert(false);
+		}
+
+		void postvisit( const ast::MemberExpr * memberExpr ) {
+			addCandidate( memberExpr, tenv );
+		}
+
+		void postvisit( const ast::NameExpr * variableExpr ) {
+			#warning unimplemented
+			(void)variableExpr;
+			assert(false);
+		}
+
+		void postvisit( const ast::VariableExpr * variableExpr ) {
+			// not sufficient to just pass `variableExpr` here, type might have changed since
+			// creation
+			addCandidate( 
+				new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
+		}
+
+		void postvisit( const ast::ConstantExpr * constantExpr ) {
+			addCandidate( constantExpr, tenv );
+		}
+
+		void postvisit( const ast::SizeofExpr * sizeofExpr ) {
+			#warning unimplemented
+			(void)sizeofExpr;
+			assert(false);
+		}
+
+		void postvisit( const ast::AlignofExpr * alignofExpr ) {
+			#warning unimplemented
+			(void)alignofExpr;
+			assert(false);
+		}
+
+		void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
+			#warning unimplemented
+			(void)offsetofExpr;
+			assert(false);
+		}
+
+		void postvisit( const ast::OffsetofExpr * offsetofExpr ) {
+			addCandidate( offsetofExpr, tenv );
+		}
+
+		void postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
+			addCandidate( offsetPackExpr, tenv );
+		}
+
+		void postvisit( const ast::LogicalExpr * logicalExpr ) {
+			CandidateFinder finder1{ symtab, tenv };
+			finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
+			if ( finder1.candidates.empty() ) return;
+
+			CandidateFinder finder2{ symtab, tenv };
+			finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
+			if ( finder2.candidates.empty() ) return;
+
+			for ( const CandidateRef & r1 : finder1.candidates ) {
+				for ( const CandidateRef & r2 : finder2.candidates ) {
+					ast::TypeEnvironment env{ r1->env };
+					env.simpleCombine( r2->env );
+					ast::OpenVarSet open{ r1->open };
+					mergeOpenVars( open, r2->open );
+					ast::AssertionSet need;
+					mergeAssertionSet( need, r1->need );
+					mergeAssertionSet( need, r2->need );
+
+					addCandidate(
+						new ast::LogicalExpr{ 
+							logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
+						std::move( env ), std::move( open ), std::move( need ), 
+						r1->cost + r2->cost );
+				}
+			}
+		}
+
+		void postvisit( const ast::ConditionalExpr * conditionalExpr ) {
+			// candidates for condition
+			CandidateFinder finder1{ symtab, tenv };
+			finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
+			if ( finder1.candidates.empty() ) return;
+
+			// candidates for true result
+			CandidateFinder finder2{ symtab, tenv };
+			finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
+			if ( finder2.candidates.empty() ) return;
+
+			// candidates for false result
+			CandidateFinder finder3{ symtab, tenv };
+			finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
+			if ( finder3.candidates.empty() ) return;
+
+			for ( const CandidateRef & r1 : finder1.candidates ) {
+				for ( const CandidateRef & r2 : finder2.candidates ) {
+					for ( const CandidateRef & r3 : finder3.candidates ) {
+						ast::TypeEnvironment env{ r1->env };
+						env.simpleCombine( r2->env );
+						env.simpleCombine( r3->env );
+						ast::OpenVarSet open{ r1->open };
+						mergeOpenVars( open, r2->open );
+						mergeOpenVars( open, r3->open );
+						ast::AssertionSet need;
+						mergeAssertionSet( need, r1->need );
+						mergeAssertionSet( need, r2->need );
+						mergeAssertionSet( need, r3->need );
+						ast::AssertionSet have;
+
+						// unify true and false results, then infer parameters to produce new 
+						// candidates
+						ast::ptr< ast::Type > common;
+						if ( 
+							unify( 
+								r2->expr->result, r3->expr->result, env, need, have, open, symtab, 
+								common ) 
+						) {
+							#warning unimplemented
+							assert(false);
+						}
+					}
+				}
+			}
+		}
+
+		void postvisit( const ast::CommaExpr * commaExpr ) {
+			ast::TypeEnvironment env{ tenv };
+			ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env );
+			
+			CandidateFinder finder2{ symtab, env };
+			finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
+
+			for ( const CandidateRef & r2 : finder2.candidates ) {
+				addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
+			}
+		}
+
+		void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
+			addCandidate( ctorExpr, tenv );
+		}
+
+		void postvisit( const ast::ConstructorExpr * ctorExpr ) {
+			CandidateFinder finder{ symtab, tenv };
+			finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
+			for ( CandidateRef & r : finder.candidates ) {
+				addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
+			}
+		}
+
+		void postvisit( const ast::RangeExpr * rangeExpr ) {
+			// resolve low and high, accept candidates where low and high types unify
+			CandidateFinder finder1{ symtab, tenv };
+			finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
+			if ( finder1.candidates.empty() ) return;
+
+			CandidateFinder finder2{ symtab, tenv };
+			finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
+			if ( finder2.candidates.empty() ) return;
+
+			for ( const CandidateRef & r1 : finder1.candidates ) {
+				for ( const CandidateRef & r2 : finder2.candidates ) {
+					ast::TypeEnvironment env{ r1->env };
+					env.simpleCombine( r2->env );
+					ast::OpenVarSet open{ r1->open };
+					mergeOpenVars( open, r2->open );
+					ast::AssertionSet need;
+					mergeAssertionSet( need, r1->need );
+					mergeAssertionSet( need, r2->need );
+					ast::AssertionSet have;
+
+					ast::ptr< ast::Type > common;
+					if ( 
+						unify( 
+							r1->expr->result, r2->expr->result, env, need, have, open, symtab, 
+							common ) 
+					) {
+						ast::RangeExpr * newExpr = 
+							new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
+						newExpr->result = common ? common : r1->expr->result;
+						
+						#warning unimplemented
+						assert(false);
+					}
+				}
+			}
+		}
+
+		void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
+			std::vector< CandidateFinder > subCandidates = 
+				selfFinder.findSubExprs( tupleExpr->exprs );
+			std::vector< CandidateList > possibilities;
+			combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
+
+			for ( const CandidateList & subs : possibilities ) {
+				std::vector< ast::ptr< ast::Expr > > exprs;
+				exprs.reserve( subs.size() );
+				for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
+
+				ast::TypeEnvironment env;
+				ast::OpenVarSet open;
+				ast::AssertionSet need;
+				for ( const CandidateRef & sub : subs ) {
+					env.simpleCombine( sub->env );
+					mergeOpenVars( open, sub->open );
+					mergeAssertionSet( need, sub->need );
+				}
+
+				addCandidate(
+					new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) }, 
+					std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
+			}
+		}
+
+		void postvisit( const ast::TupleExpr * tupleExpr ) {
+			addCandidate( tupleExpr, tenv );
+		}
+
+		void postvisit( const ast::TupleIndexExpr * tupleExpr ) {
+			addCandidate( tupleExpr, tenv );
+		}
+
+		void postvisit( const ast::TupleAssignExpr * tupleExpr ) {
+			addCandidate( tupleExpr, tenv );
+		}
+
+		void postvisit( const ast::UniqueExpr * unqExpr ) {
+			CandidateFinder finder{ symtab, tenv };
+			finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
+			for ( CandidateRef & r : finder.candidates ) {
+				// ensure that the the id is passed on so that the expressions are "linked"
+				addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
+			}
+		}
+
+		void postvisit( const ast::StmtExpr * stmtExpr ) {
+			#warning unimplemented
+			(void)stmtExpr;
+			assert(false);
+		}
+
+		void postvisit( const ast::UntypedInitExpr * initExpr ) {
+			#warning unimplemented
+			(void)initExpr;
+			assert(false);
+		}
+
+		void postvisit( const ast::InitExpr * ) {
+			assertf( false, "CandidateFinder should never see a resolved InitExpr." );
+		}
+
+		void postvisit( const ast::DeletedExpr * ) {
+			assertf( false, "CandidateFinder should never see a DeletedExpr." );
+		}
+
+		void postvisit( const ast::GenericExpr * ) {
+			assertf( false, "_Generic is not yet supported." );
+		}
+	};
+
+	/// Prunes a list of candidates down to those that have the minimum conversion cost for a given 
+	/// return type. Skips ambiguous candidates.
+	CandidateList pruneCandidates( CandidateList & candidates ) {
+		struct PruneStruct {
+			CandidateRef candidate;
+			bool ambiguous;
+
+			PruneStruct() = default;
+			PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
+		};
+
+		// find lowest-cost candidate for each type
+		std::unordered_map< std::string, PruneStruct > selected;
+		for ( CandidateRef & candidate : candidates ) {
+			std::string mangleName;
+			{
+				ast::ptr< ast::Type > newType = candidate->expr->result;
+				candidate->env.apply( newType );
+				mangleName = Mangle::mangle( newType );
+			}
+
+			auto found = selected.find( mangleName );
+			if ( found != selected.end() ) {
+				if ( candidate->cost < found->second.candidate->cost ) {
+					PRINT(
+						std::cerr << "cost " << candidate->cost << " beats " 
+							<< found->second.candidate->cost << std::endl;
+					)
+
+					found->second = PruneStruct{ candidate };
+				} else if ( candidate->cost == found->second.candidate->cost ) {
+					// if one of the candidates contains a deleted identifier, can pick the other, 
+					// since deleted expressions should not be ambiguous if there is another option 
+					// that is at least as good
+					if ( findDeletedExpr( candidate->expr ) ) {
+						// do nothing
+						PRINT( std::cerr << "candidate is deleted" << std::endl; )
+					} else if ( findDeletedExpr( found->second.candidate->expr ) ) {
+						PRINT( std::cerr << "current is deleted" << std::endl; )
+						found->second = PruneStruct{ candidate };
+					} else {
+						PRINT( std::cerr << "marking ambiguous" << std::endl; )
+						found->second.ambiguous = true;
+					}
+				} else {
+					PRINT(
+						std::cerr << "cost " << candidate->cost << " loses to " 
+							<< found->second.candidate->cost << std::endl;
+					)
+				}
+			} else {
+				selected.emplace_hint( found, mangleName, candidate );
+			}
+		}
+
+		// report unambiguous min-cost candidates
+		CandidateList out;
+		for ( auto & target : selected ) {
+			if ( target.second.ambiguous ) continue;
+
+			CandidateRef cand = target.second.candidate;
+			
+			ast::ptr< ast::Type > newResult = cand->expr->result;
+			cand->env.applyFree( newResult );
+			cand->expr = ast::mutate_field(
+				cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
+			
+			out.emplace_back( cand );
+		}
+		return out;
+	}
+
+} // anonymous namespace
+
 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
-	#warning unimplemented
-	(void)expr; (void)mode;
-	assert(false);
+	// Find alternatives for expression
+	ast::Pass<Finder> finder{ *this };
+	expr->accept( finder );
+
+	if ( mode.failFast && candidates.empty() ) {
+		SemanticError( expr, "No reasonable alternatives for expression " );
+	}
+
+	if ( mode.satisfyAssns || mode.prune ) {
+		// trim candidates to just those where the assertions are satisfiable
+		// - necessary pre-requisite to pruning
+		CandidateList satisfied;
+		std::vector< std::string > errors;
+		for ( auto & candidate : candidates ) {
+			satisfyAssertions( *candidate, symtab, satisfied, errors );
+		}
+
+		// fail early if none such
+		if ( mode.failFast && satisfied.empty() ) {
+			std::ostringstream stream;
+			stream << "No alternatives with satisfiable assertions for " << expr << "\n";
+			for ( const auto& err : errors ) {
+				stream << err;
+			}
+			SemanticError( expr->location, stream.str() );
+		}
+
+		// reset candidates
+		candidates = std::move( satisfied );
+	}
+
+	if ( mode.prune ) {
+		// trim candidates to single best one
+		PRINT(
+			std::cerr << "alternatives before prune:" << std::endl;
+			print( std::cerr, candidates );
+		)
+
+		CandidateList pruned = pruneCandidates( candidates );
+		
+		if ( mode.failFast && pruned.empty() ) {
+			std::ostringstream stream;
+			CandidateList winners = findMinCost( candidates );
+			stream << "Cannot choose between " << winners.size() << " alternatives for "
+				"expression\n";
+			ast::print( stream, expr );
+			stream << " Alternatives are:\n";
+			print( stream, winners, 1 );
+			SemanticError( expr->location, stream.str() );
+		}
+
+		auto oldsize = candidates.size();
+		candidates = std::move( pruned );
+
+		PRINT(
+			std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
+		)
+		PRINT(
+			std::cerr << "there are " << candidates.size() << " alternatives after elimination" 
+				<< std::endl;
+		)
+	}
+
+	// adjust types after pruning so that types substituted by pruneAlternatives are correctly 
+	// adjusted
+	if ( mode.adjust ) {
+		for ( CandidateRef & r : candidates ) {
+			r->expr = ast::mutate_field( 
+				r->expr.get(), &ast::Expr::result, 
+				adjustExprType( r->expr->result, r->env, symtab ) );
+		}
+	}
+
+	// Central location to handle gcc extension keyword, etc. for all expressions
+	for ( CandidateRef & r : candidates ) {
+		if ( r->expr->extension != expr->extension ) {
+			r->expr.get_and_mutate()->extension = expr->extension;
+		}
+	}
+}
+
+std::vector< CandidateFinder > CandidateFinder::findSubExprs( 
+	const std::vector< ast::ptr< ast::Expr > > & xs 
+) {
+	std::vector< CandidateFinder > out;
+
+	for ( const auto & x : xs ) {
+		out.emplace_back( symtab, env );
+		out.back().find( x, ResolvMode::withAdjustment() );
+		
+		PRINT(
+			std::cerr << "findSubExprs" << std::endl;
+			print( std::cerr, out.back().candidates );
+		)
+	}
+
+	return out;
 }
 
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -19,4 +19,5 @@
 #include "ResolvMode.h"
 #include "AST/Fwd.hpp"
+#include "AST/Node.hpp"
 #include "AST/SymbolTable.hpp"
 #include "AST/TypeEnvironment.hpp"
@@ -29,5 +30,5 @@
 	const ast::SymbolTable & symtab;         ///< Symbol table to lookup candidates
 	const ast::TypeEnvironment & env;        ///< Substitutions performed in this resolution
-	const ast::Type * targetType = nullptr;  ///< Target type for resolution
+	ast::ptr< ast::Type > targetType = nullptr;  ///< Target type for resolution
 
 	CandidateFinder( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
@@ -36,4 +37,17 @@
 	/// Fill candidates with feasible resolutions for `expr`
 	void find( const ast::Expr * expr, ResolvMode mode = {} );
+
+	/// Runs new candidate finder on each element in xs, returning the list of finders
+	std::vector< CandidateFinder > findSubExprs( const std::vector< ast::ptr< ast::Expr > > & xs );
+
+	using value_type = CandidateList::value_type;
+	using iterator = CandidateList::iterator;
+	using const_iterator = CandidateList::const_iterator;
+
+	iterator begin() { return candidates.begin(); }
+	const_iterator begin() const { return candidates.begin(); }
+	
+	iterator end() { return candidates.end(); }
+	const_iterator end() const { return candidates.end(); }
 };
 
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/CurrentObject.cc	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -946,5 +946,78 @@
 	}
 
-	void CurrentObject::setNext( const ast::Designation * designation ) {
+	const Designation * CurrentObject::findNext( const Designation * designation ) {
+		using DesignatorChain = std::deque< ptr< Expr > >;
+		PRINT( std::cerr << "___findNext" << std::endl; )
+		
+		// find all the d's
+		std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
+		std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes;
+		for ( const Expr * expr : designation->designators ) {
+			PRINT( std::cerr << "____untyped: " << expr << std::endl; )
+			auto dit = desigAlts.begin();
+			if ( auto nexpr = dynamic_cast< const NameExpr * >( expr ) ) {
+				for ( const Type * t : curTypes ) {
+					assert( dit != desigAlts.end() );
+
+					DesignatorChain & d = *dit;
+					PRINT( std::cerr << "____actual: " << t << std::endl; )
+					if ( auto refType = dynamic_cast< const ReferenceToType * >( t ) ) {
+						// concatenate identical field names
+						for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
+							if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
+								PRINT( std::cerr << "____alt: " << field->type << std::endl; )
+								DesignatorChain d2 = d;
+								d2.emplace_back( new VariableExpr{ expr->location, field } );
+								newDesigAlts.emplace_back( std::move( d2 ) );
+								newTypes.emplace_back( field->type );
+							}
+						}
+					}
+
+					++dit;
+				}
+			} else {
+				for ( const Type * t : curTypes ) {
+					assert( dit != desigAlts.end() );
+
+					DesignatorChain & d = *dit;
+					if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
+						PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
+						d.emplace_back( expr );
+						newDesigAlts.emplace_back( d );
+						newTypes.emplace_back( at->base );
+					}
+				}
+			}
+
+			// reset queue
+			desigAlts = std::move( newDesigAlts );
+			newDesigAlts.clear();
+			curTypes = std::move( newTypes );
+			newTypes.clear();
+			assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
+		}
+
+		if ( desigAlts.size() > 1 ) {
+			SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
+		} else if ( desigAlts.empty() ) {
+			SemanticError( designation, "No reasonable alternatives for designation: " );
+		}
+
+		DesignatorChain & d = desigAlts.back();
+		PRINT( for ( Expression * expr : d ) {
+			std::cerr << "____desig: " << expr << std::endl;
+		} ) // for
+		assertf( ! curTypes.empty(), "empty designator chosen");
+
+		// set new designators
+		assertf( ! objStack.empty(), "empty object stack when setting designation" );
+		Designation * actualDesignation = 
+			new Designation{ designation->location, DesignatorChain{d} };
+		objStack.back()->setPosition( d ); // destroys d
+		return actualDesignation;
+	}
+
+	void CurrentObject::setNext( const Designation * designation ) {
 		PRINT( std::cerr << "____setNext" << designation << std::endl; )
 		assertf( ! objStack.empty(), "obj stack empty in setNext" );
Index: src/ResolvExpr/CurrentObject.h
===================================================================
--- src/ResolvExpr/CurrentObject.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/CurrentObject.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -111,4 +111,6 @@
 		CurrentObject( const CodeLocation & loc, const Type * type );
 
+		/// resolves unresolved designation
+		const Designation * findNext( const Designation * designation );
 		/// sets current position using the resolved designation
 		void setNext( const ast::Designation * designation );
Index: src/ResolvExpr/ExplodedActual.cc
===================================================================
--- src/ResolvExpr/ExplodedActual.cc	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/ExplodedActual.cc	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Alternative.h --
+// ExplodedActual.cc --
 //
 // Author           : Aaron B. Moss
@@ -24,2 +24,8 @@
 	}
 }
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/ExplodedActual.h
===================================================================
--- src/ResolvExpr/ExplodedActual.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/ExplodedActual.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Alternative.h --
+// ExplodedActual.h --
 //
 // Author           : Aaron B. Moss
@@ -37,2 +37,8 @@
 	};
 }
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/ExplodedArg.cpp
===================================================================
--- src/ResolvExpr/ExplodedArg.cpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ src/ResolvExpr/ExplodedArg.cpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,31 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ExplodedArg.cpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Tue Jun 11 16:18:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Tue Jun 11 16:18:00 2019
+// Update Count     : 1
+//
+
+#include "ExplodedArg.hpp"
+
+#include "Tuples/Explode.h"   // for Tuples::explode
+
+namespace ResolvExpr {
+
+ExplodedArg::ExplodedArg( const Candidate & arg, const ast::SymbolTable & symtab )
+: env( arg.env ), cost( arg.cost ), exprs() { Tuples::explode( arg, symtab, *this ); }
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/ExplodedArg.hpp
===================================================================
--- src/ResolvExpr/ExplodedArg.hpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ src/ResolvExpr/ExplodedArg.hpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,48 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ExplodedArg.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Tue Jun 11 16:18:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Tue Jun 11 16:18:00 2019
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <vector>
+
+#include "Candidate.hpp"            // for Candidate, CandidateList
+#include "Cost.h"                   // for Cost
+#include "AST/Expr.hpp"
+#include "AST/Node.hpp"             // for ptr
+#include "AST/TypeEnvironment.hpp"  // for TypeEnvironment
+#include "AST/SymbolTable.hpp"      // for SymbolTable
+
+namespace ResolvExpr {
+
+/// Pre-exploded argument
+struct ExplodedArg {
+	ast::TypeEnvironment env;
+	Cost cost;
+	std::vector< ast::ptr<ast::Expr> > exprs;
+
+	ExplodedArg() : env(), cost( Cost::zero ), exprs() {}
+	ExplodedArg( const Candidate & arg, const ast::SymbolTable & symtab );
+	
+	ExplodedArg( ExplodedArg && ) = default;
+	ExplodedArg & operator= ( ExplodedArg && ) = default;
+};
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/ResolvMode.h
===================================================================
--- src/ResolvExpr/ResolvMode.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/ResolvMode.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -22,13 +22,13 @@
 		const bool prune;            ///< Prune alternatives to min-cost per return type? [true]
 		const bool failFast;         ///< Fail on no resulting alternatives? [true]
-		const bool resolveAssns;     ///< Resolve assertions? [false]
+		const bool satisfyAssns;     ///< Satisfy assertions? [false]
 
 	private:
-		constexpr ResolvMode(bool a, bool p, bool ff, bool ra) 
-		: adjust(a), prune(p), failFast(ff), resolveAssns(ra) {}
+		constexpr ResolvMode(bool a, bool p, bool ff, bool sa) 
+		: adjust(a), prune(p), failFast(ff), satisfyAssns(sa) {}
 
 	public:
 		/// Default settings
-		constexpr ResolvMode() : adjust(false), prune(true), failFast(true), resolveAssns(false) {}
+		constexpr ResolvMode() : adjust(false), prune(true), failFast(true), satisfyAssns(false) {}
 		
 		/// With adjust flag set; turns array and function types into equivalent pointers
@@ -43,5 +43,5 @@
 		static constexpr ResolvMode withoutFailFast() { return { true, true, false, false }; }
 
-		/// The same mode, but with resolveAssns turned on; for top-level calls
+		/// The same mode, but with satisfyAssns turned on; for top-level calls
 		ResolvMode atTopLevel() const { return { adjust, prune, failFast, true }; }
 	};
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/Resolver.cc	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -35,4 +35,5 @@
 #include "AST/Print.hpp"
 #include "AST/SymbolTable.hpp"
+#include "AST/Type.hpp"
 #include "Common/PassVisitor.h"          // for PassVisitor
 #include "Common/SemanticError.h"        // for SemanticError
@@ -956,12 +957,14 @@
 			}
 		};
-
-		/// 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;
-		}
-
+	} // anonymous namespace
+
+	/// 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;
+	}
+
+	namespace {
 		/// always-accept candidate filter
 		bool anyCandidate( const Candidate & ) { return true; }
@@ -1023,7 +1026,5 @@
 
 			// promote candidate.cvtCost to .cost
-			for ( CandidateRef & cand : winners ) {
-				cand->cost = cand->cvtCost;
-			}
+			promoteCvtCost( winners );
 
 			// produce ambiguous errors, if applicable
@@ -1099,25 +1100,26 @@
 			StripCasts_new::strip( expr );
 		}
-
-		/// Find the expression candidate that is the unique best match for `untyped` in a `void`
-		/// context.
-		ast::ptr< ast::Expr > resolveInVoidContext(
-			const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env
-		) {
-			assertf( expr, "expected a non-null expression" );
-			
-			// set up and resolve expression cast to void
-			ast::CastExpr * untyped = new ast::CastExpr{ expr->location, expr };
-			CandidateRef choice = findUnfinishedKindExpression( 
-				untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
-			
-			// a cast expression has either 0 or 1 interpretations (by language rules);
-			// if 0, an exception has already been thrown, and this code will not run
-			const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
-			env = std::move( choice->env );
-
-			return castExpr->arg;
-		}
-
+	} // anonymous namespace
+
+		
+	ast::ptr< ast::Expr > resolveInVoidContext(
+		const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env
+	) {
+		assertf( expr, "expected a non-null expression" );
+		
+		// set up and resolve expression cast to void
+		ast::CastExpr * untyped = new ast::CastExpr{ expr->location, expr };
+		CandidateRef choice = findUnfinishedKindExpression( 
+			untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
+		
+		// a cast expression has either 0 or 1 interpretations (by language rules);
+		// if 0, an exception has already been thrown, and this code will not run
+		const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
+		env = std::move( choice->env );
+
+		return castExpr->arg;
+	}
+
+	namespace {
 		/// Resolve `untyped` to the expression whose candidate is the best match for a `void` 
 		/// context.
@@ -1146,4 +1148,11 @@
 		}
 
+		/// Resolve `untyped` to the single expression whose candidate is the best match
+		ast::ptr< ast::Expr > findSingleExpression( 
+			const ast::Expr * untyped, const ast::SymbolTable & symtab 
+		) {
+			return findKindExpression( untyped, symtab );
+		}
+
 		/// Resolve `untyped` to the single expression whose candidate is the best match for the 
 		/// given type.
@@ -1152,6 +1161,6 @@
 		) {
 			assert( untyped && type );
-			const ast::Expr * castExpr = new ast::CastExpr{ untyped->location, untyped, type };
-			ast::ptr< ast::Expr > newExpr = findKindExpression( castExpr, symtab );
+			ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped->location, untyped, type };
+			ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
 			removeExtraneousCast( newExpr, symtab );
 			return newExpr;
@@ -1189,4 +1198,11 @@
 			return false;
 		}
+
+		/// Advance a type itertor to the next mutex parameter
+		template<typename Iter>
+		inline bool nextMutex( Iter & it, const Iter & end ) {
+			while ( it != end && ! (*it)->get_type()->is_mutex() ) { ++it; }
+			return it != end;
+		}
 	}
 
@@ -1213,21 +1229,21 @@
 		void previsit( const ast::PointerType * );
 
-		const ast::ExprStmt *   previsit( const ast::ExprStmt * );
-		const ast::AsmExpr *    previsit( const ast::AsmExpr * );
-		const ast::AsmStmt *    previsit( const ast::AsmStmt * );
-		const ast::IfStmt *     previsit( const ast::IfStmt * );
-		const ast::WhileStmt *  previsit( const ast::WhileStmt * );
-		const ast::ForStmt *    previsit( const ast::ForStmt * );
-		const ast::SwitchStmt * previsit( const ast::SwitchStmt * );
-		const ast::CaseStmt *   previsit( const ast::CaseStmt * );
-		const ast::BranchStmt * previsit( const ast::BranchStmt * );
-		const ast::ReturnStmt * previsit( const ast::ReturnStmt * );
-		const ast::ThrowStmt *  previsit( const ast::ThrowStmt * );
-		const ast::CatchStmt *  previsit( const ast::CatchStmt * );
-		void previsit( const ast::WaitForStmt * );
-
-		const ast::SingleInit * previsit( const ast::SingleInit * );
-		const ast::ListInit * previsit( const ast::ListInit * );
-		void previsit( const ast::ConstructorInit * );
+		const ast::ExprStmt *        previsit( const ast::ExprStmt * );
+		const ast::AsmExpr *         previsit( const ast::AsmExpr * );
+		const ast::AsmStmt *         previsit( const ast::AsmStmt * );
+		const ast::IfStmt *          previsit( const ast::IfStmt * );
+		const ast::WhileStmt *       previsit( const ast::WhileStmt * );
+		const ast::ForStmt *         previsit( const ast::ForStmt * );
+		const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
+		const ast::CaseStmt *        previsit( const ast::CaseStmt * );
+		const ast::BranchStmt *      previsit( const ast::BranchStmt * );
+		const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
+		const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
+		const ast::CatchStmt *       previsit( const ast::CatchStmt * );
+		const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
+
+		const ast::SingleInit *      previsit( const ast::SingleInit * );
+		const ast::ListInit *        previsit( const ast::ListInit * );
+		const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
 	};
 
@@ -1381,7 +1397,7 @@
 				"expression." );
 			
-			const ast::Expr * untyped = 
+			ast::ptr< ast::Expr > untyped = 
 				new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
-			ast::ptr< ast::Expr > newExpr = findKindExpression( untyped, symtab );
+			ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, symtab );
 			
 			// case condition cannot have a cast in C, so it must be removed here, regardless of 
@@ -1401,9 +1417,8 @@
 		if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
 			// computed goto argument is void*
+			ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
 			branchStmt = ast::mutate_field(
 				branchStmt, &ast::BranchStmt::computedTarget, 
-				findSingleExpression( 
-					branchStmt->computedTarget, new ast::PointerType{ new ast::VoidType{} }, 
-					symtab ) );
+				findSingleExpression( branchStmt->computedTarget, target, symtab ) );
 		}
 		return branchStmt;
@@ -1445,8 +1460,254 @@
 	}
 
-	void Resolver_new::previsit( const ast::WaitForStmt * stmt ) {
-		#warning unimplemented; Resolver port in progress
-		(void)stmt;
-		assert(false);
+	const ast::WaitForStmt * Resolver_new::previsit( const ast::WaitForStmt * stmt ) {
+		visit_children = false;
+
+		// Resolve all clauses first
+		for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
+			const ast::WaitForStmt::Clause & clause = stmt->clauses[i];
+
+			ast::TypeEnvironment env;
+			CandidateFinder funcFinder{ symtab, env };
+
+			// Find all candidates for a function in canonical form
+			funcFinder.find( clause.target.func, ResolvMode::withAdjustment() );
+
+			if ( funcFinder.candidates.empty() ) {
+				stringstream ss;
+				ss << "Use of undeclared indentifier '";
+				ss << clause.target.func.strict_as< ast::NameExpr >()->name;
+				ss << "' in call to waitfor";
+				SemanticError( stmt->location, ss.str() );
+			}
+
+			if ( clause.target.args.empty() ) {
+				SemanticError( stmt->location, 
+					"Waitfor clause must have at least one mutex parameter");
+			}
+
+			// Find all alternatives for all arguments in canonical form
+			std::vector< CandidateFinder > argFinders = 
+				funcFinder.findSubExprs( clause.target.args );
+			
+			// List all combinations of arguments
+			std::vector< CandidateList > possibilities;
+			combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
+
+			// For every possible function:
+			// * try matching the arguments to the parameters, not the other way around because 
+			//   more arguments than parameters
+			CandidateList funcCandidates;
+			std::vector< CandidateList > argsCandidates;
+			SemanticErrorException errors;
+			for ( CandidateRef & func : funcFinder.candidates ) {
+				try {
+					auto pointerType = dynamic_cast< const ast::PointerType * >( 
+						func->expr->result->stripReferences() );
+					if ( ! pointerType ) {
+						SemanticError( stmt->location, func->expr->result.get(), 
+							"candidate not viable: not a pointer type\n" );
+					}
+
+					auto funcType = pointerType->base.as< ast::FunctionType >();
+					if ( ! funcType ) {
+						SemanticError( stmt->location, func->expr->result.get(), 
+							"candidate not viable: not a function type\n" );
+					}
+
+					{
+						auto param    = funcType->params.begin();
+						auto paramEnd = funcType->params.end();
+
+						if( ! nextMutex( param, paramEnd ) ) {
+							SemanticError( stmt->location, funcType, 
+								"candidate function not viable: no mutex parameters\n");
+						}
+					}
+
+					CandidateRef func2{ new Candidate{ *func } };
+					// strip reference from function
+					func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
+
+					// Each argument must be matched with a parameter of the current candidate
+					for ( auto & argsList : possibilities ) {
+						try {
+							// Declare data structures needed for resolution
+							ast::OpenVarSet open;
+							ast::AssertionSet need, have;
+							ast::TypeEnvironment resultEnv{ func->env };
+							// Add all type variables as open so that those not used in the 
+							// parameter list are still considered open
+							resultEnv.add( funcType->forall );
+
+							// load type variables from arguments into one shared space
+							for ( auto & arg : argsList ) {
+								resultEnv.simpleCombine( arg->env );
+							}
+
+							// Make sure we don't widen any existing bindings
+							resultEnv.forbidWidening();
+
+							// Find any unbound type variables
+							resultEnv.extractOpenVars( open );
+
+							auto param = funcType->params.begin();
+							auto paramEnd = funcType->params.end();
+
+							unsigned n_mutex_param = 0;
+
+							// For every argument of its set, check if it matches one of the 
+							// parameters. The order is important
+							for ( auto & arg : argsList ) {
+								// Ignore non-mutex arguments
+								if ( ! nextMutex( param, paramEnd ) ) {
+									// We ran out of parameters but still have arguments.
+									// This function doesn't match
+									SemanticError( stmt->location, funcType, 
+										toString("candidate function not viable: too many mutex "
+										"arguments, expected ", n_mutex_param, "\n" ) );
+								}
+
+								++n_mutex_param;
+
+								// Check if the argument matches the parameter type in the current 
+								// scope
+								ast::ptr< ast::Type > paramType = (*param)->get_type();
+								if ( 
+									! unify( 
+										arg->expr->result, paramType, resultEnv, need, have, open, 
+										symtab ) 
+								) {
+									// Type doesn't match
+									stringstream ss;
+									ss << "candidate function not viable: no known conversion "
+										"from '";
+									ast::print( ss, (*param)->get_type() );
+									ss << "' to '";
+									ast::print( ss, arg->expr->result );
+									ss << "' with env '";
+									ast::print( ss, resultEnv );
+									ss << "'\n";
+									SemanticError( stmt->location, funcType, ss.str() );
+								}
+
+								++param;
+							}
+
+							// All arguments match!
+
+							// Check if parameters are missing
+							if ( nextMutex( param, paramEnd ) ) {
+								do {
+									++n_mutex_param;
+									++param;
+								} while ( nextMutex( param, paramEnd ) );
+
+								// We ran out of arguments but still have parameters left; this 
+								// function doesn't match
+								SemanticError( stmt->location, funcType, 
+									toString( "candidate function not viable: too few mutex "
+									"arguments, expected ", n_mutex_param, "\n" ) );
+							}
+
+							// All parameters match!
+
+							// Finish the expressions to tie in proper environments
+							finishExpr( func2->expr, resultEnv );
+							for ( CandidateRef & arg : argsList ) {
+								finishExpr( arg->expr, resultEnv );
+							}
+
+							// This is a match, store it and save it for later
+							funcCandidates.emplace_back( std::move( func2 ) );
+							argsCandidates.emplace_back( std::move( argsList ) );
+
+						} catch ( SemanticErrorException & e ) {
+							errors.append( e );
+						}
+					}
+				} catch ( SemanticErrorException & e ) {
+					errors.append( e );
+				}
+			}
+
+			// Make sure correct number of arguments
+			if( funcCandidates.empty() ) {
+				SemanticErrorException top( stmt->location, 
+					"No alternatives for function in call to waitfor" );
+				top.append( errors );
+				throw top;
+			}
+
+			if( argsCandidates.empty() ) {
+				SemanticErrorException top( stmt->location, 
+					"No alternatives for arguments in call to waitfor" ); 
+				top.append( errors );
+				throw top;
+			}
+
+			if( funcCandidates.size() > 1 ) {
+				SemanticErrorException top( stmt->location, 
+					"Ambiguous function in call to waitfor" );
+				top.append( errors );
+				throw top;
+			}
+			if( argsCandidates.size() > 1 ) {
+				SemanticErrorException top( stmt->location,
+					"Ambiguous arguments in call to waitfor" );
+				top.append( errors );
+				throw top;
+			}
+			// TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
+
+			// build new clause
+			ast::WaitForStmt::Clause clause2;
+			
+			clause2.target.func = funcCandidates.front()->expr;
+			
+			clause2.target.args.reserve( clause.target.args.size() );
+			for ( auto arg : argsCandidates.front() ) {
+				clause2.target.args.emplace_back( std::move( arg->expr ) );
+			}
+
+			// Resolve the conditions as if it were an IfStmt, statements normally
+			clause2.cond = findSingleExpression( clause.cond, symtab );
+			clause2.stmt = clause.stmt->accept( *visitor );
+
+			// set results into stmt
+			auto n = mutate( stmt );
+			n->clauses[i] = std::move( clause2 );
+			stmt = n;
+		}
+
+		if ( stmt->timeout.stmt ) {
+			// resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
+			ast::WaitForStmt::Timeout timeout2;
+
+			ast::ptr< ast::Type > target = 
+				new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
+			timeout2.time = findSingleExpression( stmt->timeout.time, target, symtab );
+			timeout2.cond = findSingleExpression( stmt->timeout.cond, symtab );
+			timeout2.stmt = stmt->timeout.stmt->accept( *visitor );
+
+			// set results into stmt
+			auto n = mutate( stmt );
+			n->timeout = std::move( timeout2 );
+			stmt = n;
+		}
+
+		if ( stmt->orElse.stmt ) {
+			// resolve the condition like IfStmt, stmts normally
+			ast::WaitForStmt::OrElse orElse2;
+
+			orElse2.cond = findSingleExpression( stmt->orElse.cond, symtab );
+			orElse2.stmt = stmt->orElse.stmt->accept( *visitor );
+
+			// set results into stmt
+			auto n = mutate( stmt );
+			n->orElse = std::move( orElse2 );
+			stmt = n;
+		}
+
+		return stmt;
 	}
 
@@ -1457,7 +1718,7 @@
 		// resolve initialization using the possibilities as determined by the `currentObject` 
 		// cursor.
-		ast::Expr * untyped = new ast::UntypedInitExpr{ 
+		ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{ 
 			singleInit->location, singleInit->value, currentObject.getOptions() };
-		ast::ptr<ast::Expr> newExpr = findKindExpression( untyped, symtab );
+		ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, symtab );
 		const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
 
@@ -1510,7 +1771,14 @@
 			// iterate designations and initializers in pairs, moving the cursor to the current 
 			// designated object and resolving the initializer against that object
-			#warning unimplemented; Resolver port in progress
-			assert(false);
-		}
+			listInit = ast::mutate_field_index(
+				listInit, &ast::ListInit::designations, i, 
+				currentObject.findNext( listInit->designations[i] ) );
+			listInit = ast::mutate_field_index(
+				listInit, &ast::ListInit::initializers, i,
+				listInit->initializers[i]->accept( *visitor ) );
+		}
+
+		// move cursor out of brace-enclosed initializer-list
+		currentObject.exitListInit();
 
 		visit_children = false;
@@ -1518,8 +1786,23 @@
 	}
 
-	void Resolver_new::previsit( const ast::ConstructorInit * ctorInit ) {
-		#warning unimplemented; Resolver port in progress
-		(void)ctorInit;
-		assert(false);
+	const ast::ConstructorInit * Resolver_new::previsit( const ast::ConstructorInit * ctorInit ) {
+		visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
+		visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
+
+		// found a constructor - can get rid of C-style initializer
+		// xxx - Rob suggests this field is dead code
+		ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
+
+		// intrinsic single-parameter constructors and destructors do nothing. Since this was 
+		// implicitly generated, there's no way for it to have side effects, so get rid of it to 
+		// clean up generated code
+		if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
+			ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
+		}
+		if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
+			ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
+		}
+
+		return ctorInit;
 	}
 
Index: src/ResolvExpr/Resolver.h
===================================================================
--- src/ResolvExpr/Resolver.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/Resolver.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -17,5 +17,6 @@
 
 #include <list>          // for list
-#include <AST/Node.hpp>  // for ptr
+
+#include "AST/Node.hpp"  // for ptr
 
 class ConstructorInit;
@@ -29,4 +30,7 @@
 namespace ast {
 	class Decl;
+	class DeletedExpr;
+	class SymbolTable;
+	class TypeEnvironment;
 } // namespace ast
 
@@ -48,4 +52,10 @@
 	/// Checks types and binds syntactic constructs to typed representations
 	void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );
+	/// Searches expr and returns the first DeletedExpr found, otherwise nullptr
+	const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
+	/// Find the expression candidate that is the unique best match for `untyped` in a `void`
+	/// context.
+	ast::ptr< ast::Expr > resolveInVoidContext(
+		const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env );
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/SatisfyAssertions.cpp
===================================================================
--- src/ResolvExpr/SatisfyAssertions.cpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ src/ResolvExpr/SatisfyAssertions.cpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,37 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// SatisfyAssertions.cpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Mon Jun 10 17:45:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 10 17:45:00 2019
+// Update Count     : 1
+//
+
+#include "SatisfyAssertions.hpp"
+
+#include <cassert>
+
+namespace ResolvExpr {
+
+void satisfyAssertions( 
+	Candidate & alt, const ast::SymbolTable & symtab, CandidateList & out, 
+	std::vector<std::string> & errors
+) {
+	#warning unimplemented
+	(void)alt; (void)symtab; (void)out; (void)errors;
+	assert(false);
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/SatisfyAssertions.hpp
===================================================================
--- src/ResolvExpr/SatisfyAssertions.hpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ src/ResolvExpr/SatisfyAssertions.hpp	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,40 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// SatisfyAssertions.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Mon Jun 10 17:45:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 10 17:45:00 2019
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "Candidate.hpp"  // for Candidate, CandidateList
+
+namespace ast {
+	class SymbolTable;
+}
+
+namespace ResolvExpr {
+
+/// Recursively satisfies all assertions provided in a candidate; returns true if succeeds
+void satisfyAssertions( 
+	Candidate & alt, const ast::SymbolTable & symtab, CandidateList & out, 
+	std::vector<std::string> & errors );
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/Unify.cc	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -1143,4 +1143,13 @@
 			const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, 
 			ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 
+			ast::OpenVarSet & open, const ast::SymbolTable & symtab
+	) {
+		ast::ptr<ast::Type> common;
+		return unify( type1, type2, env, need, have, open, symtab, common );
+	}
+
+	bool unify( 
+			const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, 
+			ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 
 			ast::OpenVarSet & open, const ast::SymbolTable & symtab, ast::ptr<ast::Type> & common 
 	) {
Index: src/ResolvExpr/Unify.h
===================================================================
--- src/ResolvExpr/Unify.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/Unify.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -72,4 +72,9 @@
 		const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, 
 		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 
+		ast::OpenVarSet & open, const ast::SymbolTable & symtab );
+
+	bool unify( 
+		const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, 
+		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 
 		ast::OpenVarSet & open, const ast::SymbolTable & symtab, ast::ptr<ast::Type> & common );
 
Index: src/ResolvExpr/module.mk
===================================================================
--- src/ResolvExpr/module.mk	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/module.mk	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -26,4 +26,5 @@
       ResolvExpr/CurrentObject.cc \
       ResolvExpr/ExplodedActual.cc \
+      ResolvExpr/ExplodedArg.cpp \
       ResolvExpr/FindOpenVars.cc \
       ResolvExpr/Occurs.cc \
@@ -35,4 +36,5 @@
       ResolvExpr/Resolver.cc \
       ResolvExpr/ResolveTypeof.cc \
+      ResolvExpr/SatisfyAssertions.cpp \
       ResolvExpr/SpecCost.cc \
       ResolvExpr/TypeEnvironment.cc \
Index: src/ResolvExpr/typeops.h
===================================================================
--- src/ResolvExpr/typeops.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/ResolvExpr/typeops.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -71,4 +71,8 @@
 		} // while
 	}
+
+	/// Replaces array types with equivalent pointer, and function types with a pointer-to-function
+	const ast::Type * adjustExprType( 
+		const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab );
 
 	// in CastCost.cc
Index: src/Tuples/Explode.h
===================================================================
--- src/Tuples/Explode.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/Tuples/Explode.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -19,9 +19,16 @@
 #include <utility>                      // for forward
 
+#include "AST/Expr.hpp"
 #include "ResolvExpr/Alternative.h"     // for Alternative, AltList
+#include "ResolvExpr/Candidate.hpp"     // for Candidate, CandidateList
 #include "ResolvExpr/ExplodedActual.h"  // for ExplodedActual
+#include "ResolvExpr/ExplodedArg.hpp"   // for ExplodedArg
 #include "SynTree/Expression.h"         // for Expression, UniqueExpr, AddressExpr
 #include "SynTree/Type.h"               // for TupleType, Type
 #include "Tuples.h"                     // for maybeImpure
+
+namespace ast {
+	class SymbolTable;
+}
 
 namespace SymTab {
@@ -130,4 +137,25 @@
 		explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );
 	}
+
+/// helper function used by explode
+template< typename Output >
+void explodeUnique( 
+	const ast::Expr * expr, const ResolvExpr::Candidate & arg, const ast::SymbolTable & symtab, 
+	Output && out, bool isTupleAssign
+) {
+	#warning unimplemented
+	(void)expr; (void)arg; (void)symtab; (void)out; (void)isTupleAssign;
+	assert(false);
+}
+
+/// expands a tuple-valued candidate into multiple candidates, each with a non-tuple type
+template< typename Output >
+void explode( 
+	const ResolvExpr::Candidate & arg, const ast::SymbolTable & symtab, Output && out, 
+	bool isTupleAssign = false
+) {
+	explodeUnique( arg.expr, arg, symtab, std::forward< Output >( out ), isTupleAssign );
+}
+
 } // namespace Tuples
 
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/Tuples/TupleAssignment.cc	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -377,4 +377,13 @@
 		}
 	}
+
+	void handleTupleAssignment( 
+		ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, 
+		std::vector< ResolvExpr::CandidateFinder > & args
+	) {
+		#warning unimplmented
+		(void)finder; (void)assign; (void)args;
+		assert(false);
+	}
 } // namespace Tuples
 
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ src/Tuples/Tuples.h	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -26,4 +26,5 @@
 
 #include "ResolvExpr/AlternativeFinder.h"
+#include "ResolvExpr/CandidateFinder.hpp"
 
 namespace Tuples {
@@ -31,4 +32,7 @@
 	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
 		std::vector< ResolvExpr::AlternativeFinder >& args );
+	void handleTupleAssignment( 
+		ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, 
+		std::vector< ResolvExpr::CandidateFinder > & args );
 
 	// TupleExpansion.cc
Index: tests/.expect/manipulatorsInput.txt
===================================================================
--- tests/.expect/manipulatorsInput.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ tests/.expect/manipulatorsInput.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,92 @@
+1 yyyyyyyyyyyyyyyyyyyy
+2 abcxxx
+3 abcxxx
+4 aaaaaaaa
+5 aaaaaaaa
+6 aabbccbb
+7 dddwww
+8 dddwww
+9 dddwww
+10 aaaaaaaa
+11 wwwwwwww
+12 wwwwwwww
+13 wwwwwwww
+1 yyyyyyyyyyyyyyyyyyyy
+2 abcxxx
+3 abcxxx
+4 aaaaaaaa
+5 aaaaaaaa
+6 aabbccbb
+7 dddwww
+8 dddwww
+9 dddwww
+10 aaaaaaaa
+11 wwwwwwww
+12 wwwwwwww
+13 wwwwwwww
+a
+a
+-1
+15
+15
+15
+255
+15
+15
+15
+255
+15
+15
+15
+255
+15
+15
+15
+255
+15
+15
+15
+255
+15
+15
+15
+255
+15
+15
+15
+255
+15
+15
+15
+255
+15
+15
+15
+255
+15
+15
+15
+3.5
+345.6
+345.6
+345.6
+3.5
+345.6
+345.6
+345.6
+3.5
+345.6
+345.6
+345.6
+3.5+3.5i
+345.6+345.6i
+345.6+345.6i
+345.6+345.6i
+3.5+3.5i
+345.6+345.6i
+345.6+345.6i
+345.6+345.6i
+3.5+3.5i
+345.6+345.6i
+345.6+345.6i
+345.6+345.6i
Index: tests/.expect/manipulatorsOutput1.txt
===================================================================
--- tests/.expect/manipulatorsOutput1.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ tests/.expect/manipulatorsOutput1.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,50 @@
+signed char
+-12 -12   -12 -12   364 0364 f4 0xf4     0xf4 0x00000000f4    0X0F4 -012     -0000012
+-12 -12   -12 -12   364 0364 f4 0xf4     0xf4 0x00000000f4    0X0F4 -012     -0000012
+unsigned char
+12 12    12 12    14 014 c 0xc      0xc 0x000000000c    0X00C 012      00000012
+12 12    12 12    14 014 c 0xc      0xc 0x000000000c    0X00C 012      00000012
+signed short int
+-12 -12   -12 -12   177764 0177764 fff4 0xfff4   0xfff4 0x000000fff4   0XFFF4 -012     -0000012
+-12 -12   -12 -12   177764 0177764 fff4 0xfff4   0xfff4 0x000000fff4   0XFFF4 -012     -0000012
+unsigned short int
+12 12    12 12    14 014 c 0xc      0xc 0x000000000c    0X00C 012      00000012
+12 12    12 12    14 014 c 0xc      0xc 0x000000000c    0X00C 012      00000012
+signed int
+-12 -12   -12 -12   37777777764 037777777764 fffffff4 0xfffffff4 0xfffffff4 0x00fffffff4 0XFFFFFFF4 -012     -0000012
+-12 -12   -12 -12   37777777764 037777777764 fffffff4 0xfffffff4 0xfffffff4 0x00fffffff4 0XFFFFFFF4 -012     -0000012
+unsigned int
+12 12    12 12    14 014 c 0xc      0xc 0x000000000c    0X00C 012      00000012
+12 12    12 12    14 014 c 0xc      0xc 0x000000000c    0X00C 012      00000012
+signed long long int
+-12 -12   -12 -12   1777777777777777777764 01777777777777777777764 fffffffffffffff4 0xfffffffffffffff4 0xfffffffffffffff4 0xfffffffffffffff4 0XFFFFFFFFFFFFFFF4 -012     -0000012
+-12 -12   -12 -12   1777777777777777777764 01777777777777777777764 fffffffffffffff4 0xfffffffffffffff4 0xfffffffffffffff4 0xfffffffffffffff4 0XFFFFFFFFFFFFFFF4 -012     -0000012
+unsigned long long int
+12 12    12 12    14 014 c 0xc      0xc 0x000000000c    0X00C 012      00000012
+12 12    12 12    14 014 c 0xc      0xc 0x000000000c    0X00C 012      00000012
+
+binary integral
+0b0 0b1101 0B1101 1101 0b1101     0b1101 0b1101   0b001101 0b0000001101 0b001101
+
+float
+0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0. 3.000000 3.000000 3.537 3.537000        4        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+double
+0  3.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0. 3.000000 3.537 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+long double
+0  3.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
+0. 3.000000 3.53699999999999992 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
+
+char
+a  a     a a     141 0141 61 0x61     0x61     0X61 a               a
+a  a     a a     141 0141 61 0x61     0x61     0X61 a               a
+
+string
+abcd     abcd   abcd abcd    
+abcd     abcd   abcd abcd    
+
+binary string
+0b110000 0b1100001 0b1100010 0b1100011 0b1100100 0141 0142 0143 0144 0x61 0x62 0x63 0x64
+110000 1100001 1100010 1100011 1100100 141 142 143 144 61 62 63 64
+  110000  1100001  1100010  1100011  1100100  141  142  143  144  61  62  63  64
Index: tests/.expect/manipulatorsOutput2.x64.txt
===================================================================
--- tests/.expect/manipulatorsOutput2.x64.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ tests/.expect/manipulatorsOutput2.x64.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,32 @@
+
+0b0 0b11011 0b11011 0b11011 0b11011
+0b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b1111111111111111111111111111111111111111111111111111111111100101
+0 033 033 033 033
+0345 0177745 037777777745 01777777777777777777745
+0 0x1b 0x1b 0x1b 0x1b
+0xe5 0xffe5 0xffffffe5 0xffffffffffffffe5
+0x0p+0. 0x1.b8p+4 0x1.b8p+4 0xd.cp+1
+-0x1.b8p+4 -0x1.b8p+4 -0xd.cp+1
+0.000000e+00 2.750000e+01 -2.750000e+01
+0B11011 0X1B 2.75E-09 0X1.B8P+4
+11011 33 1b
+0. 0 27. 27 27.5
++27 -27 +27 -27 +27.5 -27.5
+  34  34 34
+  4.000000  4.000000 4.000000
+  ab  ab ab
+34567 34567 34567
+3456.000000 3456.000000 3456.000000
+abcde abcde abcde
+ 034     0034 0000000034
+3456     3456       3456
+     0000000034
+27.500     27.5      28. 27.50000000
+27.000 27.500     27.5      28. 27.50000000
+27   27.000000  27.500000  027  27.500    
+234.567 234.57  234.6   235.
+234567. 2.3457e+05 2.346e+05 2.35e+05
+234567. 234567. 234567. 234567.
+  abcd     abcd abcd
+  abcd abcdefgh    abc
+0027  027 0027.500
Index: tests/.expect/manipulatorsOutput2.x86.txt
===================================================================
--- tests/.expect/manipulatorsOutput2.x86.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ tests/.expect/manipulatorsOutput2.x86.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,32 @@
+
+0b0 0b11011 0b11011 0b11011 0b11011
+0b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b11111111111111111111111111100101
+0 033 033 033 033
+0345 0177745 037777777745 037777777745
+0 0x1b 0x1b 0x1b 0x1b
+0xe5 0xffe5 0xffffffe5 0xffffffe5
+0x0p+0. 0x1.b8p+4 0x1.b8p+4 0xd.cp+1
+-0x1.b8p+4 -0x1.b8p+4 -0xd.cp+1
+0.000000e+00 2.750000e+01 -2.750000e+01
+0B11011 0X1B 2.75E-09 0X1.B8P+4
+11011 33 1b
+0. 0 27. 27 27.5
++27 -27 +27 -27 +27.5 -27.5
+  34  34 34
+  4.000000  4.000000 4.000000
+  ab  ab ab
+34567 34567 34567
+3456.000000 3456.000000 3456.000000
+abcde abcde abcde
+ 034     0034 0000000034
+3456     3456       3456
+     0000000034
+27.500     27.5      28. 27.50000000
+27.000 27.500     27.5      28. 27.50000000
+27   27.000000  27.500000  027  27.500    
+234.567 234.57  234.6   235.
+234567. 2.3457e+05 2.346e+05 2.35e+05
+234567. 234567. 234567. 234567.
+  abcd     abcd abcd
+  abcd abcdefgh    abc
+0027  027 0027.500
Index: tests/.in/manipulatorsInput.txt
===================================================================
--- tests/.in/manipulatorsInput.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ tests/.in/manipulatorsInput.txt	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,29 @@
+abc 
+abc 
+xx
+abcxxx
+abcyyy
+aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww
+abc 
+abc 
+xx
+abcxxx
+abcyyy
+aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww
+ab
+0xff 017 15-15
+0xff 017 15-15
+0xff 017 15-15
+0xff 017 15-15
+0xff 017 15-15
+0xff 017 15-15
+0xff 017 15-15
+0xff 017 15-15
+0xff 017 15-15
+0xff 017 15-15
+3.5 3.456E+2 -0x1.2p-3 0X1.23p3
+3.5 3.456E+2 -0x1.2p-3 0X1.23p3
+3.5 3.456E+2 -0x1.2p-3 0X1.23p3
+3.5 3.5 3.456E+23.456E+2 -0x1.2p-3 3.5 0X1.23p3     3.5
+3.5 3.5 3.456E+23.456E+2 -0x1.2p-3 3.5 0X1.23p3     3.5
+3.5 3.5 3.456E+23.456E+2 -0x1.2p-3 3.5 0X1.23p3     3.5
Index: tests/manipulatorsInput.cfa
===================================================================
--- tests/manipulatorsInput.cfa	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ tests/manipulatorsInput.cfa	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,157 @@
+// 
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+// 
+// manipulatorsInput.cfa -- 
+// 
+// Author           : Peter A. Buhr
+// Created On       : Sat Jun  8 17:58:54 2019
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon Jun 10 18:38:35 2019
+// Update Count     : 8
+// 
+
+#include <fstream.hfa>
+#include <stdio.h>					// scanf
+
+int main() {
+	{
+		char s[] = "yyyyyyyyyyyyyyyyyyyy";
+		scanf( "abc" );			printf( "1 %s\n", s );
+		scanf( "%s", s );					printf( "2 %s\n", s );
+		scanf( "%*s" );						printf( "3 %s\n", s );
+		scanf( "%8s", s );					printf( "4 %s\n", s );
+		scanf( "%*8s" );					printf( "5 %s\n", s );
+
+		scanf( "%[abc]", s );				printf( "6 %s\n", s );
+		scanf( "%[^abc]", s );				printf( "7 %s\n", s );
+		scanf( "%*[abc]" );					printf( "8 %s\n", s );
+		scanf( "%*[^abc]" );				printf( "9 %s\n", s );
+		scanf( "%8[abc]", s );				printf( "10 %s\n", s );
+		scanf( "%8[^abc]", s );				printf( "11 %s\n", s );
+		scanf( "%*8[abc]" );				printf( "12 %s\n", s );
+		scanf( "%*8[^abc]" );				printf( "13 %s\n", s );
+	}
+	{
+		char s[] = "yyyyyyyyyyyyyyyyyyyy";
+		sin | skip( "abc" );					sout | "1" | s;
+		sin | cstr( s );						sout | "2" | s;
+		sin | ignore( cstr( s ) );				sout | "3" | s;
+		sin | wd( 8, cstr( s ) );				sout | "4" | s;
+		sin | ignore( wd( 8, cstr( s ) ) );		sout | "5" | s;
+
+		sin | incl( "abc", s );					sout | "6" | s;
+		sin | excl( "abc", s );					sout | "7" | s;
+		sin | ignore( incl( "abc", s ) );		sout | "8" | s;
+		sin | ignore( excl( "abc", s ) );		sout | "9" | s;
+		sin | wd( 8, incl( "abc", s ) );		sout | "10" | s;
+		sin | wd( 8, excl( "abc", s ) );		sout | "11" | s;
+		sin | ignore( wd( 8, incl( "abc", s ) ) );	sout | "12" | s;
+		sin | ignore( wd( 8, excl( "abc", s ) ) );	sout | "13" | s;
+	}
+	{
+		char c;
+		sin | c;							sout | c;
+		sin | ignore( c );					sout | c;
+
+		signed char sc;
+		sin | sc;							sout | sc;
+		sin | wdi( 3, sc );					sout | sc;
+		sin | ignore( sc );					sout | sc;
+		sin | ignore( wdi( 3, sc ) );		sout | sc;
+
+		unsigned char usc;
+		sin | usc;							sout | usc;
+		sin | wdi( 3, usc );				sout | usc;
+		sin | ignore( usc );				sout | usc;
+		sin | ignore( wdi( 3, usc ) );		sout | usc;
+
+		signed short int ssi;
+		sin | ssi;							sout | ssi;
+		sin | wdi( 3, ssi );				sout | ssi;
+		sin | ignore( ssi );				sout | ssi;
+		sin | ignore( wdi( 3, ssi ) );		sout | ssi;
+
+		unsigned short int usi;
+		sin | usi;							sout | usi;
+		sin | wdi( 3, usi );				sout | usi;
+		sin | ignore( usi );				sout | usi;
+		sin | ignore( wdi( 3, usi ) );		sout | usi;
+
+		signed int si;
+		sin | si;							sout | si;
+		sin | wdi( 3, si );					sout | si;
+		sin | ignore( si );					sout | si;
+		sin | ignore( wdi( 3, si ) );		sout | si;
+
+		unsigned int ui;
+		sin | ui;							sout | ui;
+		sin | wdi( 3, ui );					sout | ui;
+		sin | ignore( ui );					sout | ui;
+		sin | ignore( wdi( 3, ui ) );		sout | ui;
+
+		signed long int sli;
+		sin | sli;							sout | sli;
+		sin | wdi( 3, sli );				sout | sli;
+		sin | ignore( sli );				sout | sli;
+		sin | ignore( wdi( 3, sli ) );		sout | sli;
+
+		unsigned long int uli;
+		sin | uli;							sout | uli;
+		sin | wdi( 3, uli );				sout | uli;
+		sin | ignore( uli );				sout | uli;
+		sin | ignore( wdi( 3, uli ) );		sout | uli;
+
+		signed long long int slli;
+		sin | slli;							sout | slli;
+		sin | wdi( 3, slli );				sout | slli;
+		sin | ignore( slli );				sout | slli;
+		sin | ignore( wdi( 3, slli ) );		sout | slli;
+
+		unsigned long long int ulli;
+		sin | ulli;							sout | ulli;
+		sin | wdi( 3, ulli );				sout | ulli;
+		sin | ignore( ulli );				sout | ulli;
+		sin | ignore( wdi( 3, ulli ) );		sout | ulli;
+
+		float f;
+		sin | f;							sout | f;
+		sin | wdi( 8, f );					sout | f;
+		sin | ignore( f );					sout | f;
+		sin | ignore( wdi( 8, f ) );		sout | f;
+
+		double d;
+		sin | d;							sout | d;
+		sin | wdi( 8, d );					sout | d;
+		sin | ignore( d );					sout | d;
+		sin | ignore( wdi( 8, d ) );		sout | d;
+
+		long double ld;
+		sin | ld;							sout | ld;
+		sin | wdi( 8, ld );					sout | ld;
+		sin | ignore( ld );					sout | ld;
+		sin | ignore( wdi( 8, ld ) );		sout | ld;
+
+		float _Complex fc;
+		sin | fc;							sout | fc;
+		sin | wdi( 8, fc );					sout | fc;
+		sin | ignore( fc );					sout | fc;
+		sin | ignore( wdi( 8, fc ) );		sout | fc;
+
+		double _Complex dc;
+		sin | dc;							sout | dc;
+		sin | wdi( 8, dc );					sout | dc;
+		sin | ignore( dc );					sout | dc;
+		sin | ignore( wdi( 8, dc ) );		sout | dc;
+
+		long double _Complex ldc;
+		sin | ldc;							sout | ldc;
+		sin | wdi( 8, ldc );				sout | ldc;
+		sin | ignore( ldc );				sout | ldc;
+		sin | ignore( wdi( 8, ldc ) );		sout | ldc;
+	}
+} // main
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa manipulatorsInput.cfa" //
+// End: //
Index: tests/manipulatorsOutput1.cfa
===================================================================
--- tests/manipulatorsOutput1.cfa	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ tests/manipulatorsOutput1.cfa	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,98 @@
+// 
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+// 
+// manipulatorsOutput1.cfa -- 
+// 
+// Author           : Peter A. Buhr
+// Created On       : Sat Jun  8 18:04:11 2019
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon Jun 10 12:37:28 2019
+// Update Count     : 8
+// 
+
+#include <fstream.hfa>
+
+int main() {
+	sout | "signed char";
+	signed char sc = -12;
+	printf( "%hhd %2hhd %5.2hhd %-5.2hhd %hho %#hho %hhx %#hhx %#8hhx %#8.10hhx %#8.3hhX %+-8.3hhd %08hhd\n", sc, sc, sc, sc, sc, sc, sc, sc, sc, sc, sc, sc, sc );
+	sout | sc | wd(2,sc) | wd(5,2,sc) | left(wd(5,2,sc)) | nobase(oct(sc)) | oct(sc) | nobase(hex(sc)) | hex(sc) | wd(8,hex(sc)) | wd(8,10,hex(sc)) | upcase(wd(8,3,hex(sc))) | left(sign(upcase(wd(8,3,sc)))) | pad0(wd(8,sc));
+
+	sout | "unsigned char";
+	unsigned char usc = 12;
+	printf( "%hhu %2hhu %5.2hhu %-5.2hhu %hho %#hho %hhx %#hhx %#8hhx %#8.10hhx %#8.3hhX %-8.3hhu %08hhu\n", usc, usc, usc, usc, usc, usc, usc, usc, usc, usc, usc, usc, usc );
+	sout | usc | wd(2,usc) | wd(5,2,usc) | left(wd(5,2,usc)) | nobase(oct(usc)) | oct(usc) | nobase(hex(usc)) | hex(usc) | wd(8,hex(usc)) | wd(8,10,hex(usc)) | upcase(wd(8,3,hex(usc))) | left(upcase(wd(8,3,usc))) | pad0(wd(8,usc));
+
+	sout | "signed short int";
+	signed short int si = -12;
+	printf( "%hd %2hd %5.2hd %-5.2hd %ho %#ho %hx %#hx %#8hx %#8.10hx %#8.3hX %+-8.3hd %08hd\n", si, si, si, si, si, si, si, si, si, si, si, si, si );
+	sout | si | wd(2,si) | wd(5,2,si) | left(wd(5,2,si)) | nobase(oct(si)) | oct(si) | nobase(hex(si)) | hex(si) | wd(8,hex(si)) | wd(8,10,hex(si)) | upcase(wd(8,3,hex(si))) | left(sign(upcase(wd(8,3,si)))) | pad0(wd(8,si));
+
+	sout | "unsigned short int";
+	unsigned short int usi = 12;
+	printf( "%hu %2hu %5.2hu %-5.2hu %ho %#ho %hx %#hx %#8hx %#8.10hx %#8.3hX %-8.3hu %08hu\n", usi, usi, usi, usi, usi, usi, usi, usi, usi, usi, usi, usi, usi );
+	sout | usi | wd(2,usi) | wd(5,2,usi) | left(wd(5,2,usi)) | nobase(oct(usi)) | oct(usi) | nobase(hex(usi)) | hex(usi) | wd(8,hex(usi)) | wd(8,10,hex(usi)) | upcase(wd(8,3,hex(usi))) | left(upcase(wd(8,3,usi))) | pad0(wd(8,usi));
+
+	sout | "signed int";
+	signed int i = -12;
+	printf( "%d %2d %5.2d %-5.2d %o %#o %x %#x %#8x %#8.10x %#8.3X %+-8.3d %08d\n", i, i, i, i, i, i, i, i, i, i, i, i, i );
+	sout | i | wd(2,i) | wd(5,2,i) | left(wd(5,2,i)) | nobase(oct(i)) | oct(i) | nobase(hex(i)) | hex(i) | wd(8,hex(i)) | wd(8,10,hex(i)) | upcase(wd(8,3,hex(i))) | left(sign(upcase(wd(8,3,i)))) | pad0(wd(8,i));
+
+	sout | "unsigned int";
+	unsigned int ui = 12;
+	printf( "%u %2u %5.2u %-5.2u %o %#o %x %#x %#8x %#8.10x %#8.3X %-8.3u %08u\n", ui, ui, ui, ui, ui, ui, ui, ui, ui, ui, ui, ui, ui );
+	sout | ui | wd(2,ui) | wd(5,2,ui) | left(wd(5,2,ui)) | nobase(oct(ui)) | oct(ui) | nobase(hex(ui)) | hex(ui) | wd(8,hex(ui)) | wd(8,10,hex(ui)) | upcase(wd(8,3,hex(ui))) | left(upcase(wd(8,3,ui))) | pad0(wd(8,ui));
+
+	sout | "signed long long int";
+	signed long long int lli = -12;
+	printf( "%lld %2lld %5.2lld %-5.2lld %llo %#llo %llx %#llx %#8llx %#8.10llx %#8.3llX %+-8.3lld %08lld\n", lli, lli, lli, lli, lli, lli, lli, lli, lli, lli, lli, lli, lli );
+	sout | lli | wd(2,lli) | wd(5,2,lli) | left(wd(5,2,lli)) | nobase(oct(lli)) | oct(lli) | nobase(hex(lli)) | hex(lli) | wd(8,hex(lli)) | wd(8,10,hex(lli)) | upcase(wd(8,3,hex(lli))) | left(sign(upcase(wd(8,3,lli)))) | pad0(wd(8,lli));
+
+	sout | "unsigned long long int";
+	unsigned long long int ulli = 12;
+	printf( "%llu %2llu %5.2llu %-5.2llu %llo %#llo %llx %#llx %#8llx %#8.10llx %#8.3llX %-8.3llu %08llu\n", ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli );
+	sout | ulli | wd(2,ulli) | wd(5,2,ulli) | left(wd(5,2,ulli)) | nobase(oct(ulli)) | oct(ulli) | nobase(hex(ulli)) | hex(ulli) | wd(8,hex(ulli)) | wd(8,10,hex(ulli)) | upcase(wd(8,3,hex(ulli))) | left(upcase(wd(8,3,ulli))) | pad0(wd(8,ulli));
+
+	sout | nl | "binary integral";
+	sout | bin(0) | bin(13) | upcase(bin(13)) | nobase(bin(13)) | left(wd(8,bin(13))) | wd(8,bin(13)) | pad0(left(wd(8,bin(13)))) | pad0(wd(8,bin(13))) | pad0(wd(8,10,bin(13))) | pad0(wd(8,6,bin(13)));
+
+
+	sout | nl | "float";
+	float f = 3.537;
+	printf( "%g  %8g %#8g %g %8g %8.0g %#8.0g %8.2g %#8.2g %-8.2g %-8.2g %-#8.2g %-+8.2g %-+#8.2g %08.2g %8.2E %8.2a %#8.2A %#8.2e\n",
+		    0.0,3.0F,3.0F, f,  f,    f,     f,    f,     f,  3.0F,      f,      f,      f,       f,     f,    f,    f,     f,     f );
+	sout | 0.0 | wd(8, 3.0F) | nodp(wd(8, 3.0F)) | f | wd(8, f) | ws(8,0, f) | nodp(ws(8,0, f)) | ws(8,2, f) | nodp(ws(8,2, f)) | left(ws(8,2, 3.0F)) | left(ws(8,2, f)) | left(nodp(ws(8,2, f))) | left(sign(ws(8,2, f))) | left(sign(nodp(ws(8,2, f)))) | pad0(ws(8,2, f)) | upcase(wd(8,2, sci(f))) | wd(8,2, hex(f)) | upcase(wd(8,2, hex(f))) | nodp(wd(8,2, sci(f)));
+
+	sout | "double";
+	double d = 3.537;
+	printf( "%g  %#8f %g %8f %#8.0f %8.0f %8.2f %-8.2f %-+#8.2f %08.2F %8.2E %8.2a %8.2A %8.2e\n",
+			0.0,  3.0, d,  d,     d,    d,    d,     d,       d,     d,    d,    d,    d,    d );
+	sout | 0.0 | wd(8, 3.0) | d | wd(8, d) | nodp(wd(8,0, d)) | wd(8,0, d) | wd(8,2, d) | left(wd(8,2, d)) | left(sign(wd(8,2, d))) | pad0(upcase(wd(8,2, d))) | upcase(wd(8,2, sci(d))) | wd(8,2, hex(d)) | upcase(wd(8,2, hex(d))) | wd(8,2, sci(d));
+
+	sout | "long double";
+	long double ld = 3.537;
+	printf( "%Lg  %#8Lf %Lg %8Lf %#8.0Lf %8.0Lf %8.2Lf %-8.2Lf %-+#8.2Lf %08.2LF %8.2LE %8.2La %8.2LA %8.2Le\n",
+			0.0L,  3.0L, ld,  ld,     ld,    ld,    ld,     ld,       ld,     ld,    ld,    ld,    ld,    ld );
+	sout | 0.0L | wd(8, 3.0L) | ld | wd(8, ld) | nodp(wd(8,0, ld)) | wd(8,0, ld) | wd(8,2, ld) | left(wd(8,2, ld)) | left(sign(wd(8,2, ld))) | pad0(upcase(wd(8,2, ld))) | upcase(wd(8,2, sci(ld))) | wd(8,2, hex(ld)) | upcase(wd(8,2, hex(ld))) | wd(8,2, sci(ld));
+
+
+	sout | nl | "char";
+	char c = 'a';
+	printf( "%c %2c %5c %-5c %hho %#hho %hhx %#hhx %#8hhx %#8hhX %-8c %8c\n", c, c, c, c, c, c, c, c, c, c, c, c );
+	sout | c | ' ' | wd(2,c) | wd(5,c) | left(wd(5,c)) | nobase(oct(c)) | oct(c) | nobase(hex(c)) | hex(c) | wd(8,hex(c)) | upcase(wd(8,hex(c))) | left(wd(8,c)) | wd(8,c);
+
+	sout | nl | "string";
+	const char * s = "abcd";
+	printf( "%s %8s %6.8s %-8s\n", s, s, s, s );
+	sout | s | wd(8,s) | wd(6,8,s) | left(wd(8,s));
+
+	sout | nl | "binary string";
+	sout | bin("0") | bin(s) | oct(s) | hex(s);
+	sout | nobase(bin("0")) | nobase(bin(s)) | nobase(oct(s)) | nobase(hex(s));
+	sout | nobase(wd(8,bin("0"))) | nobase(wd(8,bin(s))) | nobase(wd(4,oct(s))) | nobase(wd(3,hex(s)));
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa -Wall -Wextra amanipulatorsOutput1.cfa" //
+// End: //
Index: tests/manipulatorsOutput2.cfa
===================================================================
--- tests/manipulatorsOutput2.cfa	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
+++ tests/manipulatorsOutput2.cfa	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -0,0 +1,55 @@
+// 
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+// 
+// manipulatorsOutput2.cfa -- 
+// 
+// Author           : Peter A. Buhr
+// Created On       : Sat Jun  8 18:04:11 2019
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon Jun 10 12:37:57 2019
+// Update Count     : 8
+// 
+
+#include <fstream.hfa>
+
+int main() {
+	sout | nl;
+    sout | bin(0) | bin(27HH) | bin(27H) | bin(27) | bin(27L);
+    sout | bin(-27HH) | bin(-27H) | bin(-27) | bin(-27L);
+    sout | oct(0) | oct(27HH) | oct(27H) | oct(27) | oct(27L);
+    sout | oct(-27HH) | oct(-27H) | oct(-27) | oct(-27L);
+    sout | hex(0) | hex(27HH) | hex(27H) | hex(27) | hex(27L);
+    sout | hex(-27HH) | hex(-27H) | hex(-27) | hex(-27L);
+    sout | hex(0.0) | hex(27.5F) | hex(27.5) | hex(27.5L);
+    sout | hex(-27.5F) | hex(-27.5) | hex(-27.5L);
+	sout | sci(0.0) | sci(27.5) | sci(-27.5);
+	sout | upcase(bin(27)) | upcase(hex(27)) | upcase(27.5e-10) | upcase(hex(27.5));
+	sout | nobase(bin(27)) | nobase(oct(27)) | nobase(hex(27));
+    sout | 0. | nodp(0.) | 27.0 | nodp(27.0) | nodp(27.5);
+    sout | sign(27) | sign(-27) | sign(27.) | sign(-27.) | sign(27.5) | sign(-27.5);
+	sout | wd( 4, 34) | wd( 3, 34 ) | wd( 2, 34 );
+	sout | wd( 10, 4.) | wd( 9, 4. ) | wd( 8, 4. );
+	sout | wd( 4, "ab" ) | wd( 3, "ab" ) | wd( 2, "ab" );
+	sout | wd( 4, 34567 ) | wd( 3, 34567 ) | wd( 2, 34567 );
+	sout | wd( 4, 3456. ) | wd( 3, 3456. ) | wd( 2, 3456. );
+	sout | wd( 4, "abcde" ) | wd( 3, "abcde" ) | wd( 2,"abcde" );
+	sout | wd(4,3, 34) | wd(8,4, 34) | wd(10,10, 34);
+	sout | wd( 4,1, 3456 ) | wd( 8,2, 3456 ) | wd( 10,3, 3456 );
+	sout | wd( 4,0, 0 ) | wd( 3,10, 34 );
+	sout | wd(6,3, 27.5) | wd(8,1, 27.5) | wd(8,0, 27.5) | wd(3,8, 27.5);
+	sout | wd(6,3, 27.0) | wd(6,3, 27.5) | wd(8,1, 27.5) | wd(8,0, 27.5) | wd(3,8, 27.5);
+	sout | left(wd(4,27)) | left(wd(10,27.)) | left(wd(10,27.5)) | left(wd(4,3,27)) | left(wd(10,3,27.5));
+	sout | ws(6,6, 234.567) | ws(6,5, 234.567) | ws(6,4, 234.567) | ws(6,3, 234.567);
+	sout | ws(6,6, 234567.) | ws(6,5, 234567.) | ws(6,4, 234567.) | ws(6,3, 234567.);
+	sout | ws(3,6, 234567.) | ws(4,6, 234567.) | ws(5,6, 234567.) | ws(6,6, 234567.);
+	sout | wd(6, "abcd") | wd(8, "abcd") | wd(2, "abcd");
+	sout | wd(6,8, "abcd") | wd(6,8, "abcdefghijk") | wd(6,3, "abcd");
+    sout | pad0(wd(4,27)) | pad0(wd(4,3,27)) | pad0(wd(8,3,27.5));
+
+//	sexit | 3 | 4;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa -Wall -Wextra amanipulatorsOutput2.cfa" //
+// End: //
Index: tests/sum.cfa
===================================================================
--- tests/sum.cfa	(revision aaeacf4b17e26df880b846210c264be0d6cc771b)
+++ tests/sum.cfa	(revision 21300d75a007db91aebde37600bdcb7eeb14a5d5)
@@ -11,6 +11,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun May 19 11:21:02 2019
-// Update Count     : 330
+// Last Modified On : Thu Jun  6 16:18:22 2019
+// Update Count     : 333
 //
 
@@ -111,5 +111,6 @@
 	};
 	GS(int) gs;
-	gs.x = anew( size );								// create array storage for field
+	// FIX ME, resolution problem with anew not picking up the LH type
+	gs.x = (typeof(gs.x))anew( size );					// create array storage for field
 	s = 0; v = low;
 	for ( int i = 0; i < size; i += 1, v += 1 ) {
