Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/AST/Pass.hpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -113,19 +113,4 @@
 	static auto read( node_type const * node, Args&&... args ) {
 		Pass<core_t> visitor( std::forward<Args>( args )... );
-		auto const * temp = node->accept( visitor );
-		assert( temp == node );
-		return visitor.get_result();
-	}
-
-	// Versions of the above for older compilers.
-	template< typename... Args >
-	static void run( TranslationUnit & decls ) {
-		Pass<core_t> visitor;
-		accept_all( decls, visitor );
-	}
-
-	template< typename node_type, typename... Args >
-	static auto read( node_type const * node ) {
-		Pass<core_t> visitor;
 		auto const * temp = node->accept( visitor );
 		assert( temp == node );
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/AST/Print.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -1579,11 +1579,11 @@
 		preprint( node );
 		os << "enum attr ";
-        if ( node->attr == ast::EnumAttribute::Label ) {
-            os << "Label ";
-        } else if ( node->attr == ast::EnumAttribute::Value ) {
-            os << "Value ";
-        } else {
-            os << "Posn ";
-        }
+		if ( node->attr == ast::EnumAttribute::Label ) {
+			os << "Label ";
+		} else if ( node->attr == ast::EnumAttribute::Value ) {
+			os << "Value ";
+		} else {
+			os << "Posn ";
+		}
 		(*(node->instance)).accept( *this );
 		return node;
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/AST/Type.hpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -31,5 +31,5 @@
 // Must be included in *all* AST classes; should be #undef'd at the end of the file
 #define MUTATE_FRIEND \
-    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * mutate(const node_t * node); \
 	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
 
@@ -322,12 +322,12 @@
 public:
 	readonly<EnumInstType> instance;
-    EnumAttribute attr;
+	EnumAttribute attr;
 	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
 	EnumAttrType( const EnumInstType * instance, EnumAttribute attr = EnumAttribute::Posn )
 		: instance(instance), attr(attr) {}
-	
-    bool match( const ast::EnumAttrType * other) const {
-        return instance->base->name == other->instance->base->name && attr == other->attr;
-    }
+
+	bool match( const ast::EnumAttrType * other) const {
+		return instance->base->name == other->instance->base->name && attr == other->attr;
+	}
 private:
 	EnumAttrType * clone() const override { return new EnumAttrType{ *this }; }
Index: src/AST/porting.md
===================================================================
--- src/AST/porting.md	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ 	(revision )
@@ -1,336 +1,0 @@
-# Porting notes for new AST #
-
-## Pointer Types ##
-* raw pointer `T*` is used for construction, but not storage
-* `ast::ptr_base<T,R>` is a pointer to AST node `T` with reference type `R`
-  * specialization: strong pointer `ast::ptr<T>` is used for an ownership relationship
-  * specialization: weak pointer `ast::readonly<T>` is used for an observation relationship
-* added `ast::ptr_base<T,R>::as<S>()` with same semantics as `dynamic_cast<S*>(p)`
-* added `N * ast::ptr_base<N,R>::set_and_mutate( const N * n )`
-  * takes ownership of `n`, then returns a mutable version owned by this pointer
-  * Some debate on whether this is a good approach:
-    * makes an easy path to cloning, which we were trying to eliminate
-      * counter-point: these are all mutating clones rather than lifetime-preserving clones, and thus "necessary" (for some definition)
-    * existing uses:
-      * `VariableExpr::VariableExpr`, `UntypedExpr::createDeref`
-        * both involve grabbing a type from elsewhere and making an `lvalue` copy of it
-        * could potentially be replaced by a view class something like this:
-          ```
-          template<unsigned Quals>
-          class AddQualifiersType final : public Type {
-            readonly<Type> base;
-            // ...
-          };
-          ```
-          * requires all `qualifiers` use (and related helpers) to be virtual, non-zero overhead
-          * also subtle semantic change, where mutations to the source decl now change the viewing expression
-
-## Visitors ##
-* `Visitor` and `Mutator` are combined into a single `ast::Visitor` class
-  * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0`
-* `PassVisitor` is replaced with `ast::Pass`
-  * Most one shot uses can use `ast::Pass::run` and `ast::Pass::read`.
-
-`WithConstTypeSubstitution`
-* `env` => `typeSubs`
-
-## Structural Changes ##
-`CodeLocation` has been devolved from `BaseSyntaxNode` to `ast::ParseNode`
-* excludes `ast::Type` from carrying location information
-* `CodeLocation` is a mandatory constructor field for `ast::ParseNode`
-  * all subclass constructors must fill it; by convention, from their first argument
-
-`N->print(std::ostream&)` is a visitor now
-* `Declaration::printShort` is also integrated
-
-`clone` is private to `Node` now
-* still needs to be overriden to return appropriate type
-  * e.g. `private: virtual Stmt * clone() const override = 0;`
-  * because friendship is not inherited, all implementations of clone need
-      /// Must be copied in ALL derived classes
-      template<typename node_t>
-      friend node_t * mutate(const node_t * node);
-      template<typename node_t>
-      friend node_t * shallowCopy(const node_t * node);
-    or equilant.
-* You should use the `mutate` function where possible as it avoids extra copies.
-  * If you must copy use `shallowCopy` or `deepCopy` as required.
-
-All leaves of the `Node` inheritance tree are now declared `final`
-* e.g. `class CompoundStmt final : public Stmt`
-* allows compiler to optimize virtual calls to static calls if given static type
-
-Pulled `FuncSpecifiers`, `StorageClasses`, `CVQualifiers` out of `Type` into their own headers
-* Made `BFCommon` a `MakeBitfield` macro in its own header
-  * added default and field-init constructors to macro
-
-Prefer move semantics for containers passed to node constructors
-
-## Code Style ##
-
-### Files ###
-* Headers have a `.hpp` suffix
-* Source code has a `.cpp` suffix
-* All source has the project-standard leading and trailing comments
-* prefer `#pragma once` over `#ifdef` guards
-* namespaces that cover entire files don't get indented
-* The general node headers only `#include "Fwd.hpp"` if they can get away with it
-  * Anything that needs definitions goes in the .cpp file
-  * `Type.hpp` includes `Decl.hpp` so that it knows the `AggregateDecl` subclasses for `ReferenceToType::aggr()` overloads
-
-### Documentation ###
-* class, method, and field comments should use doxygen-style `///` prefix
-  * should be included on all classes
-  * should be included on any method declaration that doesn't have an obvious behaviour from either naming convention (e.g. constructor, print operator, implement visitor pattern) or an inline implementation
-* use explanatory comments with `//` wherever appropriate
-  * older comments should be maintained in porting process wherever possible
-
-### Naming ###
-* Preserve names from previous AST whenever reasonable, and get team consensus on any changes.
-* Strong justification required for private fields
-  * No `get_` prefix on getters (including for generated fields)
-    * exception is `DeclWithType::get_type()`
-* Notable changes:
-  * for concision and consistency with subclasses:
-    * `Declaration` => `ast::Decl`
-	* `DeclarationWithType` => `ast::DeclWithType`
-	* `Expression` => `ast::Expr`
-	* `Initializer` => `ast::Init`
-    * `Statement` => `ast::Stmt`
-    * `ReferenceToType` => `ast::BaseInstType`
-	* any field names should follow a similar renaming
-  * because they don't really belong to `Type` (and for consistency with `Linkage::Spec`):
-    * `Type::StorageClasses` => `ast::Storage::Classes`
-	  * `Type::Extern` etc. => `ast::Storage::Extern` etc.
-	* `Type::FuncSpecifiers` => `ast::Function::Specs`
-	  * `Type::Inline` etc. => `ast::Function::Inline` etc.
-	* `Type::Qualifiers` => `ast::CV::Qualifiers`
-	  * `Type::Const` etc. => `ast::CV::Const`
-	  * couldn't break name-dependency loop without pulling `Qualifiers` out of `Type`
-	* `LinkageSpec::Spec` => `ast::Linkage::Spec`
-	  * `LinkageSpec::Mangle` etc. => `ast::Linkage::Mangle` etc.
-	  * `LinkageSpec::linkageUpdate` => `ast::Linkage::update`
-	  * `LinkageSpec::linkageName` => `ast::Linkage::name`
-	  * `LinkageSpec::isMangled(Spec)` etc. => `Spec.is_mangled` etc.
-	  * `LinkageSpec::Intrinsic` etc. => `ast::Linkage::Intrinsic` etc.
-  * Boolean flags to `SymTab::Mangler::mangle` are now a `SymTab::Mangle::Mode` struct
-    * uses `bitfield`
-  * Because `Indexer` isn't a terribly evocative name:
-    * `SymTab::Indexer` => `ast::SymbolTable`
-    * `SymTab/Indexer.{h,cc}` => `AST/SymbolTable.{hpp,cpp}`
-    * `WithIndexer` => `WithSymbolTable`
-      * `indexer` => `symTab`
-    * `IdData::deleteStmt` => `IdData::deleter`
-    * `lookupId()` now returns a vector rather than an out-param list
-  * To avoid name collisions:
-    * `SymTab::Mangler` => `Mangle`
-  * `ResolvExpr::TypeEnvironment` => `ast::TypeEnvironment`
-    * in `AST/TypeEnvironment.hpp`
-* Boolean constructor parameters get replaced with a dedicated flag enum:
-  * e.g. `bool isVarLen;` => `enum LengthFlag { FixedLen, VariableLen };` `LengthFlag isVarLen;`
-  * field can be *read* in the existing boolean contexts, but requires documentation to write
-  * suggest naming all flag enums `FooFlag` to hint at boolean nature
-
-## Specific Nodes ##
-`Attribute`
-* `parameters` => `params`
-
-`Decl`
-* `storageClasses` => `storage`
-* `declFromId()` => `fromId()`
-  * not 100% sure about the return type here...
-
-`DeclWithType`
-* When `SymTab::Validate::Pass2` is rewritten, update comment on `mangleName` with new name of pass
-* `get_scopedMangleName()` => `scopedMangleName()`
-* `get_type()` now returns `const Type*` so can't be inadvertently mutated
-  * still with `get_` name so it doesn't conflict with subclass field names
-
-`ObjectDecl`
-* changed constructor parameter order for better defaults
-  * allows `newObject` as just default settings
-
-`FunctionDecl`
-* `params` and `returns` added.
-  * Contain the declarations of the parameters and return variables.
-  * Types should match (even be shared with) the fields of `type`.
-
-`NamedTypeDecl`
-* `parameters` => `params`
-
-`TypeDecl`
-* moved `TypeDecl::Kind` to `ast::TypeVar::Kind`
-
-`AggregateDecl`
-* `parameters` => `params`
-
-`StructDecl`
-* `makeInst` replaced by better constructor on `StructInstType`.
-
-`Expr`
-* Merged `inferParams`/`resnSlots` into union, as suggested by comment in old version
-  * does imply get_/set_ API, and some care about moving backward
-* added constructor that sets result, for benefit of types that set it directly
-
-`ApplicationExpr`
-* `function` => `func`
-
-`UntypedExpr`
-* `function` => `func`
-* removed `begin_args()` in favour of `args.begin()`
-
-`ConstantExpr`
-* inlined features of `Constant`, never used elsewhere, so removed `Constant`
-  * `Constant Constant::from_int(int)` etc. => `ConstantExpr * ConstantExpr::from_int(CodeLocation, int)`
-    * allocates new `ConstantExpr`, consistent with all existing uses
-
-`SizeofExpr`, `AlignofExpr`
-* `isType` deprecated in favour of boolean check on `type`
-  * all existing uses assume `type` set if true and don't use `expr`
-
-`LogicalExpr`
-* un-defaulted constructor parameter determining `&&` or `||`
-
-`CompoundLiteralExpr`
-* `initializer` => `init`
-
-`RangeExpr`
-* removed `set_low`, `set_high` due to disuse
-
-`TupleIndexExpr`
-* removed `set_tuple`, `set_index` due to disuse
-
-`GenericExpr`
-* `Association::isDefault` removed: `! type` is equivalent
-
-`StmtExpr`
-* `statements` => `stmts`
-
-`Init`
-* `bool maybeConstruct` => `enum ConstructFlag { DoConstruct, MaybeConstruct }`
-
-`Label`
-* `get_statement()` exclusively used for code location, replaced with `CodeLocation` field
-
-`CaseStmt` => `CaseClause`
-* `_isDefault` has been removed
-  * `isDefault` calculates value from `cond`
-  * default may not have a condition. I believe case (!default) requires a condition.
-
-`BranchStmt`
-* `Type` -> `Kind` and `type` -> `kind`
-* Constructors no longer throw SemanticErrorException:
-  * `label` constructor claims it is now considered a syntax error, replaced with assert.
-  * `computedTarget` constructor assumes `Goto`, other check would have SegFaulted.
-
-`TryStmt`
-* `block` -> `body` and `finallyBlock` -> `finally`
-
-`ThrowStmt` and `CatchStmt` => `CatchClause`
-* moved `Kind` enums to shared `ast::ExceptionKind` enum
-
-`FinallyStmt` => `FinallyClause`
-* `block` -> `body`
-
-`CompoundStmt`
-* Still a `std::list` for children, rather than `std::vector`
-  * allows more-efficient splicing for purposes of later code generation
-
-`Type`
-* `CV::Qualifiers` moved to end of constructor parameter list, defaulted to `{}`
-  * removed getter, setter in favour of public `qualifiers` field
-  * `ReferenceToType` puts a defaulted list of attributes after qualifiers
-* `forall` field split off into `ParameterizedType` subclass
-  * any type that needs it can inherit from `ParameterizedType`
-    * currently `FunctionType`, `ReferenceToType`
-* `get_qualifiers()` replaced with accessor `qualifiers()` and mutator `set_qualifiers()`
-  * `get_const()` etc. replaced with `is_const()` etc. variants
-* `referenceDepth()` now returns `unsigned` rather than `int`
-* A number of features only supported on aggregates pushed down to `ReferenceToType`:
-  * `attributes`: per docs [1] GCC only supports type attributes on aggregates and typedefs
-    * suggest adding a `TypeWithAttributes` wrapper type if this proves insufficient
-  * `getAggr()` => `aggr()`
-    * also now returns `const AggregateDecl *`
-* `genericSubstitution()` moved to own visitor in `AST/GenericSubstitution.hpp`
-  * subsumes old `makeGenericSubstitution()`
-
-`BasicType`
-* **TODO** move `kind`, `typeNames` into code generator
-
-`ReferenceToType` => `BaseInstType`
-* deleted `get_baseParameters()` from children
-  * replace with `aggr() ? aggr()->params : nullptr`
-* `parameters` => `params`
-* hoisted `lookup` implementation into parent, made non-virtual
-  * also changed to return vector rather than filling; change back if any great win for reuse
-* `baseStruct` etc. renamed to `base`
-
-`PointerType`/`ArrayType`
-* `is_array()` => `isArray()`
-* `bool isVarLen;` => `enum LengthFlag { FixedLen, VariableLen }; LengthFlag isVarLen;`
-* `bool isStatic;` => `enum DimensionFlag { DynamicDim, StaticDim }; DimensionFlag isStatic;`
-
-`FunctionType`
-* `returnVals` => `returns`
-* `parameters` => `params`
-  * Both now just point at types.
-* `bool isVarArgs;` => `enum ArgumentFlag { FixedArgs, VariableArgs }; ArgumentFlag isVarArgs;`
-
-`SueInstType`
-* Template class, with specializations and using to implement some other types:
-  * `StructInstType`, `UnionInstType` & `EnumInstType`
-  * `baseStruct`, `baseUnion` & `baseEnum` => `base`
-
-`TypeInstType`
-* `bool isFtype` => `TypeVar::Kind kind`
-
-`TypeofType`
-* `bool is_basetypeof` => `enum Kind { Typeof, Basetypeof } kind;`
-
-`TupleType`
-* removed `value_type` typedef due to likely error
-  * if readded, should be `const Type *`
-
-`AttrType`
-* did not port due to deprecation of feature
-  * feature is `type@thing` e.g. `int@MAX`
-
-`referenceToRvalueConversion`
-* now returns `const Expr *` rather than mutating argument
-
-`printAssertionSet`, `printOpenVarSet`
-* `ostream &` now first argument, for consistency
-
-`EqvClass`
-* `type` => `bound`
-
-`TypeEnvironment`
-* `makeSubstitution()` => `writeToSubstitution()`
-* `isEmpty()` => `empty()`
-* removed `clone()` in favour of explicit copies
-
-`occurs`
-* moved to be helper function in `TypeEnvironment.cpp` (its only use)
-
-`WidenMode`
-* changed `widenFirst`, `widenSecond` => `first`, `second`
-* changed `WidenMode widenMode` => `WidenMode widen`
-
-`Alternative` => `Candidate`
-* `openVars` => `open`
-
-`ExplodedActual` => `ExplodedArg`
-* `ExplodedActual.h` => `ExplodedArg.hpp`
-
-`polyCost`
-* switched order of `env`, `symtab` parameters for better consistency
-
-`findMinCost`
-* pulled out conversion cost promotion into separate `promoteCvtCost` function
-
-`resolveAssertions` => `satisfyAssertions`
-* `ResolveAssertions.h` => `SatisfyAssertions.hpp`
-* `Resn*` => `Sat*`
-
-[1] https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/Type-Attributes.html#Type-Attributes
-
Index: src/BasicTypes-gen.cc
===================================================================
--- src/BasicTypes-gen.cc	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/BasicTypes-gen.cc	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -415,5 +415,5 @@
 	code << "\t" << BYMK << endl;
 	code << "\t#define BT ast::BasicKind::" << endl;
-	code << "\tstatic const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
+	code << "\tstatic const ast::BasicKind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
 	     << "\t\t/*\t\t ";
 	for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
Index: src/CodeGen/CodeGenerator.cpp
===================================================================
--- src/CodeGen/CodeGenerator.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/CodeGen/CodeGenerator.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -167,5 +167,4 @@
 	ast::Pass<CodeGenerator> subCG( acc, subOptions );
 	// Add the forall clause.
-	// TODO: These probably should be removed by now and the assert used.
 	if ( !decl->type_params.empty() ) {
 		assertf( !options.genC, "FunctionDecl forall should not reach code generation." );
@@ -174,4 +173,7 @@
 		acc << ")" << std::endl;
 	}
+	// The forall clause should be printed early as part of the preamble.
+	output << acc.str();
+	acc.str("");
 
 	acc << mangleName( decl );
Index: src/Common/PersistentMap.h
===================================================================
--- src/Common/PersistentMap.h	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Common/PersistentMap.h	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -23,11 +23,11 @@
 #include <utility>        // for forward, move
 
-/// Wraps a hash table in a persistent data structure, using a technique based 
-/// on the persistent array in Conchon & Filliatre "A Persistent Union-Find 
+/// Wraps a hash table in a persistent data structure, using a technique based
+/// on the persistent array in Conchon & Filliatre "A Persistent Union-Find
 /// Data Structure"
 
 template<typename Key, typename Val,
-         typename Hash = std::hash<Key>, typename Eq = std::equal_to<Key>>
-class PersistentMap 
+		typename Hash = std::hash<Key>, typename Eq = std::equal_to<Key>>
+class PersistentMap
 	: public std::enable_shared_from_this<PersistentMap<Key, Val, Hash, Eq>> {
 public:
@@ -38,5 +38,5 @@
 
 	/// Types of version nodes
-	enum Mode { 
+	enum Mode {
 		BASE,  ///< Root node of version tree
 		REM,   ///< Key removal node
@@ -63,5 +63,5 @@
 		Ptr base;  ///< Modified map
 		Key key;   ///< Key removed
-		
+
 		template<typename P, typename K>
 		Rem(P&& p, K&& k) : base(std::forward<P>(p)), key(std::forward<K>(k)) {}
@@ -155,5 +155,5 @@
 				auto it = base_map.find( self.key );
 
-				base->template init<Ins>( 
+				base->template init<Ins>(
 						mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
 				base->mode = INS;
@@ -175,5 +175,5 @@
 				auto it = base_map.find( self.key );
 
-				base->template init<Ins>( 
+				base->template init<Ins>(
 						mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
 				base->mode = UPD;
@@ -267,5 +267,5 @@
 	Ptr erase(const Key& k) {
 		reroot();
-		
+
 		// exit early if key does not exist in map
 		if ( ! as<Base>().count( k ) ) return this->shared_from_this();
Index: src/Common/VectorMap.h
===================================================================
--- src/Common/VectorMap.h	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Common/VectorMap.h	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -36,13 +36,11 @@
 	typedef const value_type* pointer;
 	typedef const const_value_type* const_pointer;
-	
-	class iterator : public std::iterator< std::random_access_iterator_tag,
-	                                       value_type,
-										   difference_type,
-										   pointer,
-										   reference > {
-	friend class VectorMap;
-	friend class const_iterator;
-	
+
+	class iterator : public std::iterator<
+			std::random_access_iterator_tag,
+			value_type, difference_type, pointer, reference > {
+		friend class VectorMap;
+		friend class const_iterator;
+
 		value_type data;
 
@@ -99,5 +97,5 @@
 			return data.first == o.data.first && &data.second == &o.data.second;
 		}
-		
+
 		bool operator!= (const iterator& that) const { return !(*this == that); }
 
@@ -111,10 +109,8 @@
 	};
 
-	class const_iterator : public std::iterator< std::bidirectional_iterator_tag,
-	                                             const_value_type,
-												  difference_type,
-												  const_pointer,
-												  const_reference  > {
-	friend class VectorMap;
+	class const_iterator : public std::iterator<
+			std::bidirectional_iterator_tag,
+			const_value_type, difference_type, const_pointer, const_reference > {
+		friend class VectorMap;
 		const_value_type data;
 
@@ -181,5 +177,5 @@
 			return data.first == o.data.first && &data.second == &o.data.second;
 		}
-		
+
 		bool operator!= (const const_iterator& that) const { return !(*this == that); }
 
@@ -233,12 +229,14 @@
 
 template<typename T>
-typename VectorMap<T>::iterator operator+ (typename VectorMap<T>::difference_type i, 
-                                           const typename VectorMap<T>::iterator& it) {
+typename VectorMap<T>::iterator operator+(
+		typename VectorMap<T>::difference_type i,
+		const typename VectorMap<T>::iterator& it) {
 	return it + i;
 }
 
 template<typename T>
-typename VectorMap<T>::const_iterator operator+ (typename VectorMap<T>::difference_type i, 
-                                                 const typename VectorMap<T>::const_iterator& it) {
+typename VectorMap<T>::const_iterator operator+(
+		typename VectorMap<T>::difference_type i,
+		const typename VectorMap<T>::const_iterator& it) {
 	return it + i;
 }
Index: src/Concurrency/Actors.cpp
===================================================================
--- src/Concurrency/Actors.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Concurrency/Actors.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -28,68 +28,68 @@
 
 struct CollectactorStructDecls : public ast::WithGuards {
-    unordered_set<const StructDecl *> & actorStructDecls;
-    unordered_set<const StructDecl *>  & messageStructDecls;
-    const StructDecl ** requestDecl;
-    const EnumDecl ** allocationDecl;
-    const StructDecl ** actorDecl;
-    const StructDecl ** msgDecl;
-    StructDecl * parentDecl;
-    bool insideStruct = false;
-    bool namedDecl = false;
-
-    // finds and sets a ptr to the allocation enum, which is needed in the next pass
-    void previsit( const EnumDecl * decl ) {
-        if( decl->name == "allocation" ) *allocationDecl = decl;
-    }
-
-    // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
-    void previsit( const StructDecl * decl ) {
-        if ( !decl->body ) return;
-        if ( decl->name == "actor" ) {
-            actorStructDecls.insert( decl ); // skip inserting fwd decl
-            *actorDecl = decl;
-        } else if( decl->name == "message" ) {
-            messageStructDecls.insert( decl ); // skip inserting fwd decl
-            *msgDecl = decl;
-        } else if( decl->name == "request" ) *requestDecl = decl;
-        else {
-            GuardValue(insideStruct);
-            insideStruct = true;
-            parentDecl = mutate( decl );
-        }
-	}
-
-    // this catches structs of the form:
-    //     struct dummy_actor { actor a; };
-    // since they should be:
-    //     struct dummy_actor { inline actor; };
-    void previsit ( const ObjectDecl * decl ) {
-        if ( insideStruct && ! decl->name.empty() ) {
-            GuardValue(namedDecl);
-            namedDecl = true;
-        }
-    }
-
-    // this collects the derived actor and message struct decl ptrs
-    void postvisit( const StructInstType * node ) {
-        if ( ! *actorDecl || ! *msgDecl ) return;
-        if ( insideStruct && !namedDecl ) {
-            auto actorIter = actorStructDecls.find( node->aggr() );    
-            if ( actorIter != actorStructDecls.end() ) {
-                actorStructDecls.insert( parentDecl );
-                return;
-            }
-            auto messageIter = messageStructDecls.find( node->aggr() );
-            if ( messageIter != messageStructDecls.end() ) {
-                messageStructDecls.insert( parentDecl );
-            }
-        }
+	unordered_set<const StructDecl *> & actorStructDecls;
+	unordered_set<const StructDecl *>  & messageStructDecls;
+	const StructDecl ** requestDecl;
+	const EnumDecl ** allocationDecl;
+	const StructDecl ** actorDecl;
+	const StructDecl ** msgDecl;
+	StructDecl * parentDecl;
+	bool insideStruct = false;
+	bool namedDecl = false;
+
+	// finds and sets a ptr to the allocation enum, which is needed in the next pass
+	void previsit( const EnumDecl * decl ) {
+		if( decl->name == "allocation" ) *allocationDecl = decl;
+	}
+
+	// finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
+	void previsit( const StructDecl * decl ) {
+		if ( !decl->body ) return;
+		if ( decl->name == "actor" ) {
+			actorStructDecls.insert( decl ); // skip inserting fwd decl
+			*actorDecl = decl;
+		} else if( decl->name == "message" ) {
+			messageStructDecls.insert( decl ); // skip inserting fwd decl
+			*msgDecl = decl;
+		} else if( decl->name == "request" ) *requestDecl = decl;
+		else {
+			GuardValue(insideStruct);
+			insideStruct = true;
+			parentDecl = mutate( decl );
+		}
+	}
+
+	// this catches structs of the form:
+	//     struct dummy_actor { actor a; };
+	// since they should be:
+	//     struct dummy_actor { inline actor; };
+	void previsit ( const ObjectDecl * decl ) {
+		if ( insideStruct && ! decl->name.empty() ) {
+			GuardValue(namedDecl);
+			namedDecl = true;
+		}
+	}
+
+	// this collects the derived actor and message struct decl ptrs
+	void postvisit( const StructInstType * node ) {
+		if ( ! *actorDecl || ! *msgDecl ) return;
+		if ( insideStruct && !namedDecl ) {
+			auto actorIter = actorStructDecls.find( node->aggr() );
+			if ( actorIter != actorStructDecls.end() ) {
+				actorStructDecls.insert( parentDecl );
+				return;
+			}
+			auto messageIter = messageStructDecls.find( node->aggr() );
+			if ( messageIter != messageStructDecls.end() ) {
+				messageStructDecls.insert( parentDecl );
+			}
+		}
 	}
 
   public:
-    CollectactorStructDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
-        const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl ) 
-        : actorStructDecls( actorStructDecls ), messageStructDecls( messageStructDecls ), requestDecl( requestDecl ), 
-        allocationDecl( allocationDecl ), actorDecl(actorDecl), msgDecl(msgDecl) {}
+	CollectactorStructDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
+		const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl )
+		: actorStructDecls( actorStructDecls ), messageStructDecls( messageStructDecls ), requestDecl( requestDecl ),
+		allocationDecl( allocationDecl ), actorDecl(actorDecl), msgDecl(msgDecl) {}
 };
 
@@ -97,353 +97,353 @@
 class FwdDeclTable {
 
-    // tracks which decls we have seen so that we can hoist the FunctionDecl to the highest point possible
-    struct FwdDeclData { 
-        const StructDecl * actorDecl;
-        const StructDecl * msgDecl;
-        FunctionDecl * fwdDecl;
-        bool actorFound;
-        bool msgFound;
-
-        bool readyToInsert() { return actorFound && msgFound; }
-        bool foundActor() { actorFound = true; return readyToInsert(); }
-        bool foundMsg() { msgFound = true; return readyToInsert(); }
-
-        FwdDeclData( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) :
-            actorDecl(actorDecl), msgDecl(msgDecl), fwdDecl(fwdDecl), actorFound(false), msgFound(false) {}
-    };
-
-    // map indexed by actor struct ptr
-    // value is map of all FwdDeclData that contains said actor struct ptr
-    // inner map is indexed by the message struct ptr of FwdDeclData
-    unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> actorMap;
-
-    // this map is the same except the outer map is indexed by message ptr and the inner is indexed by actor ptr
-    unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> msgMap;
-
-    void insert( const StructDecl * decl, const StructDecl * otherDecl, unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map, FwdDeclData * data ) {
-        auto iter = map.find( decl );
-        if ( iter != map.end() ) { // if decl exists in map append data to existing inner map
-            iter->second.emplace( make_pair( otherDecl, data ) );
-        } else { // else create inner map for key
-            map.emplace( make_pair( decl, unordered_map<const StructDecl *, FwdDeclData *>( { make_pair( otherDecl, data ) } ) ) );
-        }
-    }
+	// tracks which decls we have seen so that we can hoist the FunctionDecl to the highest point possible
+	struct FwdDeclData {
+		const StructDecl * actorDecl;
+		const StructDecl * msgDecl;
+		FunctionDecl * fwdDecl;
+		bool actorFound;
+		bool msgFound;
+
+		bool readyToInsert() { return actorFound && msgFound; }
+		bool foundActor() { actorFound = true; return readyToInsert(); }
+		bool foundMsg() { msgFound = true; return readyToInsert(); }
+
+		FwdDeclData( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) :
+			actorDecl(actorDecl), msgDecl(msgDecl), fwdDecl(fwdDecl), actorFound(false), msgFound(false) {}
+	};
+
+	// map indexed by actor struct ptr
+	// value is map of all FwdDeclData that contains said actor struct ptr
+	// inner map is indexed by the message struct ptr of FwdDeclData
+	unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> actorMap;
+
+	// this map is the same except the outer map is indexed by message ptr and the inner is indexed by actor ptr
+	unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> msgMap;
+
+	void insert( const StructDecl * decl, const StructDecl * otherDecl, unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map, FwdDeclData * data ) {
+		auto iter = map.find( decl );
+		if ( iter != map.end() ) { // if decl exists in map append data to existing inner map
+			iter->second.emplace( make_pair( otherDecl, data ) );
+		} else { // else create inner map for key
+			map.emplace( make_pair( decl, unordered_map<const StructDecl *, FwdDeclData *>( { make_pair( otherDecl, data ) } ) ) );
+		}
+	}
 
   public:
-    // insert decl into table so that we can fwd declare it later (average cost: O(1))
-    void insertDecl( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) {
-        FwdDeclData * declToInsert = new FwdDeclData( actorDecl, msgDecl, fwdDecl );
-        insert( actorDecl, msgDecl, actorMap, declToInsert );
-        insert( msgDecl, actorDecl, msgMap, declToInsert );
-    }
-
-    // returns list of decls to insert after current struct decl
-    // Over the entire pass the runtime of this routine is O(r) where r is the # of receive routines
-    list<FunctionDecl *> updateDecl( const StructDecl * decl, bool isMsg ) {
-        unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map = isMsg ? msgMap : actorMap;
-        unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & otherMap =  isMsg ? actorMap : msgMap;
-        auto iter = map.find( decl );
-        list<FunctionDecl *> toInsertAfter; // this is populated with decls that are ready to insert
-        if ( iter == map.end() ) return toInsertAfter;
-        
-        // iterate over inner map
-        unordered_map<const StructDecl *, FwdDeclData *> & currInnerMap = iter->second;
-        for ( auto innerIter = currInnerMap.begin(); innerIter != currInnerMap.end(); ) {
-            FwdDeclData * currentDatum = innerIter->second;
-            bool readyToInsert = isMsg ? currentDatum->foundMsg() : currentDatum->foundActor();
-            if ( ! readyToInsert ) { ++innerIter; continue; }
-            
-            // readyToInsert is true so we are good to insert the forward decl of the message fn
-            toInsertAfter.push_back( currentDatum->fwdDecl );
-
-            // need to remove from other map before deleting
-            // find inner map in other map ( other map is actor map if original is msg map and vice versa )
-            const StructDecl * otherDecl = isMsg ? currentDatum->actorDecl : currentDatum->msgDecl;
-            auto otherMapIter = otherMap.find( otherDecl );
-
-            unordered_map<const StructDecl *, FwdDeclData *> & otherInnerMap = otherMapIter->second;
-
-            // find the FwdDeclData we need to remove in the other inner map
-            auto otherInnerIter = otherInnerMap.find( decl );
-
-            // remove references to deleted FwdDeclData from current inner map
-            innerIter = currInnerMap.erase( innerIter ); // this does the increment so no explicit inc needed
-
-            // remove references to deleted FwdDeclData from other inner map
-            otherInnerMap.erase( otherInnerIter );
-            
-            // if other inner map is now empty, remove key from other outer map
-            if ( otherInnerMap.empty() )
-                otherMap.erase( otherDecl );
-
-            // now we are safe to delete the FwdDeclData since we are done with it
-            // and we have removed all references to it from our data structures
-            delete currentDatum;
-        }
-
-        // if current inner map is now empty, remove key from outer map.
-        // Have to do this after iterating for safety
-        if ( currInnerMap.empty() )
-            map.erase( decl );
-
-        return toInsertAfter;
-    }
+	// insert decl into table so that we can fwd declare it later (average cost: O(1))
+	void insertDecl( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) {
+		FwdDeclData * declToInsert = new FwdDeclData( actorDecl, msgDecl, fwdDecl );
+		insert( actorDecl, msgDecl, actorMap, declToInsert );
+		insert( msgDecl, actorDecl, msgMap, declToInsert );
+	}
+
+	// returns list of decls to insert after current struct decl
+	// Over the entire pass the runtime of this routine is O(r) where r is the # of receive routines
+	list<FunctionDecl *> updateDecl( const StructDecl * decl, bool isMsg ) {
+		unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map = isMsg ? msgMap : actorMap;
+		unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & otherMap =  isMsg ? actorMap : msgMap;
+		auto iter = map.find( decl );
+		list<FunctionDecl *> toInsertAfter; // this is populated with decls that are ready to insert
+		if ( iter == map.end() ) return toInsertAfter;
+
+		// iterate over inner map
+		unordered_map<const StructDecl *, FwdDeclData *> & currInnerMap = iter->second;
+		for ( auto innerIter = currInnerMap.begin(); innerIter != currInnerMap.end(); ) {
+			FwdDeclData * currentDatum = innerIter->second;
+			bool readyToInsert = isMsg ? currentDatum->foundMsg() : currentDatum->foundActor();
+			if ( ! readyToInsert ) { ++innerIter; continue; }
+
+			// readyToInsert is true so we are good to insert the forward decl of the message fn
+			toInsertAfter.push_back( currentDatum->fwdDecl );
+
+			// need to remove from other map before deleting
+			// find inner map in other map ( other map is actor map if original is msg map and vice versa )
+			const StructDecl * otherDecl = isMsg ? currentDatum->actorDecl : currentDatum->msgDecl;
+			auto otherMapIter = otherMap.find( otherDecl );
+
+			unordered_map<const StructDecl *, FwdDeclData *> & otherInnerMap = otherMapIter->second;
+
+			// find the FwdDeclData we need to remove in the other inner map
+			auto otherInnerIter = otherInnerMap.find( decl );
+
+			// remove references to deleted FwdDeclData from current inner map
+			innerIter = currInnerMap.erase( innerIter ); // this does the increment so no explicit inc needed
+
+			// remove references to deleted FwdDeclData from other inner map
+			otherInnerMap.erase( otherInnerIter );
+
+			// if other inner map is now empty, remove key from other outer map
+			if ( otherInnerMap.empty() )
+				otherMap.erase( otherDecl );
+
+			// now we are safe to delete the FwdDeclData since we are done with it
+			// and we have removed all references to it from our data structures
+			delete currentDatum;
+		}
+
+		// if current inner map is now empty, remove key from outer map.
+		// Have to do this after iterating for safety
+		if ( currInnerMap.empty() )
+			map.erase( decl );
+
+		return toInsertAfter;
+	}
 };
 
 // generates the definitions of send operators for actors
-// collects data needed for next pass that does the circular defn resolution 
+// collects data needed for next pass that does the circular defn resolution
 //     for message send operators (via table above)
 struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> {
-    unordered_set<const StructDecl *> & actorStructDecls;
-    unordered_set<const StructDecl *>  & messageStructDecls;
-    const StructDecl ** requestDecl;
-    const EnumDecl ** allocationDecl;
-    const StructDecl ** actorDecl;
-    const StructDecl ** msgDecl;
-    FwdDeclTable & forwardDecls;
-
-    // generates the operator for actor message sends
+	unordered_set<const StructDecl *> & actorStructDecls;
+	unordered_set<const StructDecl *>  & messageStructDecls;
+	const StructDecl ** requestDecl;
+	const EnumDecl ** allocationDecl;
+	const StructDecl ** actorDecl;
+	const StructDecl ** msgDecl;
+	FwdDeclTable & forwardDecls;
+
+	// generates the operator for actor message sends
 	void postvisit( const FunctionDecl * decl ) {
-        // return if not of the form receive( param1, param2 ) or if it is a forward decl
-        if ( decl->name != "receive" || decl->params.size() != 2 || !decl->stmts ) return;
-
-        // the params should be references
-        const ReferenceType * derivedActorRef = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
-        const ReferenceType * derivedMsgRef = dynamic_cast<const ReferenceType *>(decl->params.at(1)->get_type());
-        if ( !derivedActorRef || !derivedMsgRef ) return;
-
-        // the references should be to struct instances
-        const StructInstType * arg1InstType = dynamic_cast<const StructInstType *>(derivedActorRef->base.get());
-        const StructInstType * arg2InstType = dynamic_cast<const StructInstType *>(derivedMsgRef->base.get());
-        if ( !arg1InstType || !arg2InstType ) return;
-
-        // If the struct instances are derived actor and message types then generate the message send routine
-        auto actorIter = actorStructDecls.find( arg1InstType->aggr() );
-        auto messageIter = messageStructDecls.find( arg2InstType->aggr() );
-        if ( actorIter != actorStructDecls.end() && messageIter != messageStructDecls.end() ) {
-            //////////////////////////////////////////////////////////////////////
-            // The following generates this wrapper for all receive(derived_actor &, derived_msg &) functions
-            /* base_actor and base_msg are output params
-            static inline allocation __CFA_receive_wrap( derived_actor & receiver, derived_msg & msg, actor ** base_actor, message ** base_msg ) {
-                base_actor = &receiver;
-                base_msg = &msg;
-                return receive( receiver, msg );
-            }
-            */
-            CompoundStmt * wrapBody = new CompoundStmt( decl->location );
-
-            // generates: base_actor = &receiver;
-            wrapBody->push_back( new ExprStmt( decl->location,
-                UntypedExpr::createAssign( decl->location, 
-                    UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_actor" ) ),
-                    new AddressExpr( decl->location, new NameExpr( decl->location, "receiver" ) )
-                )
-            ));
-
-            // generates: base_msg = &msg;
-            wrapBody->push_back( new ExprStmt( decl->location,
-                UntypedExpr::createAssign( decl->location, 
-                    UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_msg" ) ),
-                    new AddressExpr( decl->location, new NameExpr( decl->location, "msg" ) )
-                )
-            ));
-
-            // generates: return receive( receiver, msg );
-            wrapBody->push_back( new ReturnStmt( decl->location,
-                new UntypedExpr ( decl->location,
-                    new NameExpr( decl->location, "receive" ),
-                    {
-                        new NameExpr( decl->location, "receiver" ),
-                        new NameExpr( decl->location, "msg" )
-                    }
-                )
-            ));
-
-            // create receive wrapper to extract base message and actor pointer
-            // put it all together into the complete function decl from above
-            FunctionDecl * receiveWrapper = new FunctionDecl(
-                decl->location,
-                "__CFA_receive_wrap",
-                {
-                    new ObjectDecl(
-                        decl->location,
-                        "receiver",
-                        ast::deepCopy( derivedActorRef )
-                    ),
-                    new ObjectDecl(
-                        decl->location,
-                        "msg",
-                        ast::deepCopy( derivedMsgRef )
-                    ),
-                    new ObjectDecl(
-                        decl->location,
-                        "base_actor",
-                        new PointerType( new PointerType( new StructInstType( *actorDecl ) ) )
-                    ),
-                    new ObjectDecl(
-                        decl->location,
-                        "base_msg",
-                        new PointerType( new PointerType( new StructInstType( *msgDecl ) ) )
-                    )
-                },                      // params
-                {
-                    new ObjectDecl(
-                        decl->location,
-                        "__CFA_receive_wrap_ret",
-                        new EnumInstType( *allocationDecl )
-                    )
-                },
-                wrapBody,               // body
-                { Storage::Static },    // storage
-                Linkage::Cforall,       // linkage
-                {},                     // attributes
-                { Function::Inline }
-            );
-
-            declsToAddAfter.push_back( receiveWrapper );
-
-            //////////////////////////////////////////////////////////////////////
-            // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
-            /*
-                static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
-                    request new_req;
-                    allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
-                    __receive_fn fn = (__receive_fn)my_work_fn;
-                    new_req{ &receiver, &msg, fn };
-                    send( receiver, new_req );
-                    return receiver;
-                }
-            */ 
-            CompoundStmt * sendBody = new CompoundStmt( decl->location );
-
-            // Generates: request new_req;
-            sendBody->push_back( new DeclStmt(
-                decl->location,
-                new ObjectDecl(
-                    decl->location,
-                    "new_req",
-                    new StructInstType( *requestDecl )
-                )
-            ));
-            
-            // Function type is: allocation (*)( derived_actor &, derived_msg &, actor **, message ** )
-            FunctionType * derivedReceive = new FunctionType();
-            derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) );
-            derivedReceive->params.push_back( ast::deepCopy( derivedMsgRef ) );
-            derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
-            derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
-            derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
-
-            // Generates: allocation (*my_work_fn)( derived_actor &, derived_msg &, actor **, message ** ) = receive;
-            sendBody->push_back( new DeclStmt(
-                decl->location,
-                new ObjectDecl(
-                    decl->location,
-                    "my_work_fn",
-                    new PointerType( derivedReceive ),
-                    new SingleInit( decl->location, new NameExpr( decl->location, "__CFA_receive_wrap" ) )
-                )
-            ));
-
-            // Function type is: allocation (*)( actor &, message & )
-            FunctionType * genericReceive = new FunctionType();
-            genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
-            genericReceive->params.push_back( new ReferenceType( new StructInstType( *msgDecl ) ) );
-            genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
-            genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
-            genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
-
-            // Generates: allocation (*fn)( actor &, message & ) = (allocation (*)( actor &, message & ))my_work_fn;
-            // More readable synonymous code: 
-            //     typedef allocation (*__receive_fn)(actor &, message &);
-            //     __receive_fn fn = (__receive_fn)my_work_fn;
-            sendBody->push_back( new DeclStmt(
-                decl->location,
-                new ObjectDecl(
-                    decl->location,
-                    "fn",
-                    new PointerType( genericReceive ),
-                    new SingleInit( decl->location, 
-                        new CastExpr( decl->location, new NameExpr( decl->location, "my_work_fn" ), new PointerType( genericReceive ), ExplicitCast )
-                    )
-                )
-            ));
-
-            // Generates: new_req{ (actor *)&receiver, (message *)&msg, fn };
-            sendBody->push_back( new ExprStmt(
-                decl->location,
+		// return if not of the form receive( param1, param2 ) or if it is a forward decl
+		if ( decl->name != "receive" || decl->params.size() != 2 || !decl->stmts ) return;
+
+		// the params should be references
+		const ReferenceType * derivedActorRef = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
+		const ReferenceType * derivedMsgRef = dynamic_cast<const ReferenceType *>(decl->params.at(1)->get_type());
+		if ( !derivedActorRef || !derivedMsgRef ) return;
+
+		// the references should be to struct instances
+		const StructInstType * arg1InstType = dynamic_cast<const StructInstType *>(derivedActorRef->base.get());
+		const StructInstType * arg2InstType = dynamic_cast<const StructInstType *>(derivedMsgRef->base.get());
+		if ( !arg1InstType || !arg2InstType ) return;
+
+		// If the struct instances are derived actor and message types then generate the message send routine
+		auto actorIter = actorStructDecls.find( arg1InstType->aggr() );
+		auto messageIter = messageStructDecls.find( arg2InstType->aggr() );
+		if ( actorIter != actorStructDecls.end() && messageIter != messageStructDecls.end() ) {
+			//////////////////////////////////////////////////////////////////////
+			// The following generates this wrapper for all receive(derived_actor &, derived_msg &) functions
+			/* base_actor and base_msg are output params
+			static inline allocation __CFA_receive_wrap( derived_actor & receiver, derived_msg & msg, actor ** base_actor, message ** base_msg ) {
+				base_actor = &receiver;
+				base_msg = &msg;
+				return receive( receiver, msg );
+			}
+			*/
+			CompoundStmt * wrapBody = new CompoundStmt( decl->location );
+
+			// generates: base_actor = &receiver;
+			wrapBody->push_back( new ExprStmt( decl->location,
+				UntypedExpr::createAssign( decl->location,
+					UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_actor" ) ),
+					new AddressExpr( decl->location, new NameExpr( decl->location, "receiver" ) )
+				)
+			));
+
+			// generates: base_msg = &msg;
+			wrapBody->push_back( new ExprStmt( decl->location,
+				UntypedExpr::createAssign( decl->location,
+					UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_msg" ) ),
+					new AddressExpr( decl->location, new NameExpr( decl->location, "msg" ) )
+				)
+			));
+
+			// generates: return receive( receiver, msg );
+			wrapBody->push_back( new ReturnStmt( decl->location,
+				new UntypedExpr ( decl->location,
+					new NameExpr( decl->location, "receive" ),
+					{
+						new NameExpr( decl->location, "receiver" ),
+						new NameExpr( decl->location, "msg" )
+					}
+				)
+			));
+
+			// create receive wrapper to extract base message and actor pointer
+			// put it all together into the complete function decl from above
+			FunctionDecl * receiveWrapper = new FunctionDecl(
+				decl->location,
+				"__CFA_receive_wrap",
+				{
+					new ObjectDecl(
+						decl->location,
+						"receiver",
+						ast::deepCopy( derivedActorRef )
+					),
+					new ObjectDecl(
+						decl->location,
+						"msg",
+						ast::deepCopy( derivedMsgRef )
+					),
+					new ObjectDecl(
+						decl->location,
+						"base_actor",
+						new PointerType( new PointerType( new StructInstType( *actorDecl ) ) )
+					),
+					new ObjectDecl(
+						decl->location,
+						"base_msg",
+						new PointerType( new PointerType( new StructInstType( *msgDecl ) ) )
+					)
+				},                      // params
+				{
+					new ObjectDecl(
+						decl->location,
+						"__CFA_receive_wrap_ret",
+						new EnumInstType( *allocationDecl )
+					)
+				},
+				wrapBody,               // body
+				{ Storage::Static },    // storage
+				Linkage::Cforall,       // linkage
+				{},                     // attributes
+				{ Function::Inline }
+			);
+
+			declsToAddAfter.push_back( receiveWrapper );
+
+			//////////////////////////////////////////////////////////////////////
+			// The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
+			/*
+				static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
+					request new_req;
+					allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
+					__receive_fn fn = (__receive_fn)my_work_fn;
+					new_req{ &receiver, &msg, fn };
+					send( receiver, new_req );
+					return receiver;
+				}
+			*/
+			CompoundStmt * sendBody = new CompoundStmt( decl->location );
+
+			// Generates: request new_req;
+			sendBody->push_back( new DeclStmt(
+				decl->location,
+				new ObjectDecl(
+					decl->location,
+					"new_req",
+					new StructInstType( *requestDecl )
+				)
+			));
+
+			// Function type is: allocation (*)( derived_actor &, derived_msg &, actor **, message ** )
+			FunctionType * derivedReceive = new FunctionType();
+			derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) );
+			derivedReceive->params.push_back( ast::deepCopy( derivedMsgRef ) );
+			derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
+			derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
+			derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
+
+			// Generates: allocation (*my_work_fn)( derived_actor &, derived_msg &, actor **, message ** ) = receive;
+			sendBody->push_back( new DeclStmt(
+				decl->location,
+				new ObjectDecl(
+					decl->location,
+					"my_work_fn",
+					new PointerType( derivedReceive ),
+					new SingleInit( decl->location, new NameExpr( decl->location, "__CFA_receive_wrap" ) )
+				)
+			));
+
+			// Function type is: allocation (*)( actor &, message & )
+			FunctionType * genericReceive = new FunctionType();
+			genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
+			genericReceive->params.push_back( new ReferenceType( new StructInstType( *msgDecl ) ) );
+			genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
+			genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
+			genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
+
+			// Generates: allocation (*fn)( actor &, message & ) = (allocation (*)( actor &, message & ))my_work_fn;
+			// More readable synonymous code:
+			//     typedef allocation (*__receive_fn)(actor &, message &);
+			//     __receive_fn fn = (__receive_fn)my_work_fn;
+			sendBody->push_back( new DeclStmt(
+				decl->location,
+				new ObjectDecl(
+					decl->location,
+					"fn",
+					new PointerType( genericReceive ),
+					new SingleInit( decl->location,
+						new CastExpr( decl->location, new NameExpr( decl->location, "my_work_fn" ), new PointerType( genericReceive ), ExplicitCast )
+					)
+				)
+			));
+
+			// Generates: new_req{ (actor *)&receiver, (message *)&msg, fn };
+			sendBody->push_back( new ExprStmt(
+				decl->location,
 				new UntypedExpr (
-                    decl->location, 
+					decl->location,
 					new NameExpr( decl->location, "?{}" ),
 					{
 						new NameExpr( decl->location, "new_req" ),
-                        new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "receiver" ) ), new PointerType( new StructInstType( *actorDecl ) ), ExplicitCast ),
-                        new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "msg" ) ), new PointerType( new StructInstType( *msgDecl ) ), ExplicitCast ),
-                        new NameExpr( decl->location, "fn" )
+						new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "receiver" ) ), new PointerType( new StructInstType( *actorDecl ) ), ExplicitCast ),
+						new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "msg" ) ), new PointerType( new StructInstType( *msgDecl ) ), ExplicitCast ),
+						new NameExpr( decl->location, "fn" )
 					}
 				)
 			));
 
-            // Generates: send( receiver, new_req );
-            sendBody->push_back( new ExprStmt(
-                decl->location,
+			// Generates: send( receiver, new_req );
+			sendBody->push_back( new ExprStmt(
+				decl->location,
 				new UntypedExpr (
-                    decl->location,
+					decl->location,
 					new NameExpr( decl->location, "send" ),
 					{
 						{
-                            new NameExpr( decl->location, "receiver" ),
-                            new NameExpr( decl->location, "new_req" )
-                        }
+							new NameExpr( decl->location, "receiver" ),
+							new NameExpr( decl->location, "new_req" )
+						}
 					}
 				)
 			));
 
-            // Generates: return receiver;
-            sendBody->push_back( new ReturnStmt( decl->location, new NameExpr( decl->location, "receiver" ) ) );
-
-            // put it all together into the complete function decl from above
-            FunctionDecl * sendOperatorFunction = new FunctionDecl(
-                decl->location,
-                "?|?",
-                {
-                    new ObjectDecl(
-                        decl->location,
-                        "receiver",
-                        ast::deepCopy( derivedActorRef )
-                    ),
-                    new ObjectDecl(
-                        decl->location,
-                        "msg",
-                        ast::deepCopy( derivedMsgRef )
-                    )
-                },                      // params
-                {
-                    new ObjectDecl(
-                        decl->location,
-                        "receiver_ret",
-                        ast::deepCopy( derivedActorRef )
-                    )
-                },
-                nullptr,               // body
-                { Storage::Static },    // storage
-                Linkage::Cforall,       // linkage
-                {},                     // attributes
-                { Function::Inline }
-            );
-
-            // forward decls to resolve use before decl problem for '|' routines
-            forwardDecls.insertDecl( *actorIter, *messageIter , ast::deepCopy( sendOperatorFunction ) );
-
-            sendOperatorFunction->stmts = sendBody;
-            declsToAddAfter.push_back( sendOperatorFunction );
-        }
+			// Generates: return receiver;
+			sendBody->push_back( new ReturnStmt( decl->location, new NameExpr( decl->location, "receiver" ) ) );
+
+			// put it all together into the complete function decl from above
+			FunctionDecl * sendOperatorFunction = new FunctionDecl(
+				decl->location,
+				"?|?",
+				{
+					new ObjectDecl(
+						decl->location,
+						"receiver",
+						ast::deepCopy( derivedActorRef )
+					),
+					new ObjectDecl(
+						decl->location,
+						"msg",
+						ast::deepCopy( derivedMsgRef )
+					)
+				},                      // params
+				{
+					new ObjectDecl(
+						decl->location,
+						"receiver_ret",
+						ast::deepCopy( derivedActorRef )
+					)
+				},
+				nullptr,               // body
+				{ Storage::Static },    // storage
+				Linkage::Cforall,       // linkage
+				{},                     // attributes
+				{ Function::Inline }
+			);
+
+			// forward decls to resolve use before decl problem for '|' routines
+			forwardDecls.insertDecl( *actorIter, *messageIter , ast::deepCopy( sendOperatorFunction ) );
+
+			sendOperatorFunction->stmts = sendBody;
+			declsToAddAfter.push_back( sendOperatorFunction );
+		}
 	}
 
   public:
-    GenFuncsCreateTables( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
-        const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl, 
-        FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), 
-        requestDecl(requestDecl), allocationDecl(allocationDecl), actorDecl(actorDecl), msgDecl(msgDecl), forwardDecls(forwardDecls) {}
+	GenFuncsCreateTables( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
+		const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl,
+		FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
+		requestDecl(requestDecl), allocationDecl(allocationDecl), actorDecl(actorDecl), msgDecl(msgDecl), forwardDecls(forwardDecls) {}
 };
 
@@ -452,76 +452,75 @@
 // generates the forward declarations of the send operator for actor routines
 struct FwdDeclOperator : public ast::WithDeclsToAdd<> {
-    unordered_set<const StructDecl *> & actorStructDecls;
-    unordered_set<const StructDecl *>  & messageStructDecls;
-    FwdDeclTable & forwardDecls;
-
-    // handles forward declaring the message operator
-    void postvisit( const StructDecl * decl ) {
-        list<FunctionDecl *> toAddAfter;
-        auto actorIter = actorStructDecls.find( decl );
-        if ( actorIter != actorStructDecls.end() ) { // this is a derived actor decl
-            // get list of fwd decls that we can now insert
-            toAddAfter = forwardDecls.updateDecl( decl, false );
-
-            // get rid of decl from actorStructDecls since we no longer need it
-            actorStructDecls.erase( actorIter );
-        } else {
-            auto messageIter = messageStructDecls.find( decl );
-            if ( messageIter == messageStructDecls.end() ) return;
-
-            toAddAfter = forwardDecls.updateDecl( decl, true );
-
-            // get rid of decl from messageStructDecls since we no longer need it
-            messageStructDecls.erase( messageIter );
-        }
-
-        // add the fwd decls to declsToAddAfter
-        for ( FunctionDecl * func : toAddAfter ) {
-            declsToAddAfter.push_back( func );
-        }
-    }
+	unordered_set<const StructDecl *> & actorStructDecls;
+	unordered_set<const StructDecl *>  & messageStructDecls;
+	FwdDeclTable & forwardDecls;
+
+	// handles forward declaring the message operator
+	void postvisit( const StructDecl * decl ) {
+		list<FunctionDecl *> toAddAfter;
+		auto actorIter = actorStructDecls.find( decl );
+		if ( actorIter != actorStructDecls.end() ) { // this is a derived actor decl
+			// get list of fwd decls that we can now insert
+			toAddAfter = forwardDecls.updateDecl( decl, false );
+
+			// get rid of decl from actorStructDecls since we no longer need it
+			actorStructDecls.erase( actorIter );
+		} else {
+			auto messageIter = messageStructDecls.find( decl );
+			if ( messageIter == messageStructDecls.end() ) return;
+
+			toAddAfter = forwardDecls.updateDecl( decl, true );
+
+			// get rid of decl from messageStructDecls since we no longer need it
+			messageStructDecls.erase( messageIter );
+		}
+
+		// add the fwd decls to declsToAddAfter
+		for ( FunctionDecl * func : toAddAfter ) {
+			declsToAddAfter.push_back( func );
+		}
+	}
 
   public:
-    FwdDeclOperator( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls, 
-        FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), forwardDecls(forwardDecls) {}
+	FwdDeclOperator( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
+		FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), forwardDecls(forwardDecls) {}
 };
 
 void implementActors( TranslationUnit & translationUnit ) {
-    // unordered_maps to collect all derived actor and message types
-    unordered_set<const StructDecl *> actorStructDecls;
-    unordered_set<const StructDecl *> messageStructDecls;
-    FwdDeclTable forwardDecls;
-
-    // for storing through the passes
-    // these are populated with various important struct decls
-    const StructDecl * requestDeclPtr = nullptr;
-    const EnumDecl * allocationDeclPtr = nullptr;
-    const StructDecl * actorDeclPtr = nullptr;
-    const StructDecl * msgDeclPtr = nullptr;
-
-    // double pointer to modify local ptrs above
-    const StructDecl ** requestDecl = &requestDeclPtr;
-    const EnumDecl ** allocationDecl = &allocationDeclPtr;
-    const StructDecl ** actorDecl = &actorDeclPtr;
-    const StructDecl ** msgDecl = &msgDeclPtr;
-
-    // first pass collects ptrs to allocation enum, request type, and generic receive fn typedef
-    // also populates maps of all derived actors and messages
-    Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl, 
-        allocationDecl, actorDecl, msgDecl );
-
-    // check that we have found all the decls we need from <actor.hfa>, if not no need to run the rest of this pass
-    if ( !allocationDeclPtr || !requestDeclPtr || !actorDeclPtr || !msgDeclPtr ) 
-        return;
-
-    // second pass locates all receive() routines that overload the generic receive fn
-    // it then generates the appropriate operator '|' send routines for the receive routines
-    Pass<GenFuncsCreateTables>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl, 
-        allocationDecl, actorDecl, msgDecl, forwardDecls );
-
-    // The third pass forward declares operator '|' send routines
-    Pass<FwdDeclOperator>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
+	// unordered_maps to collect all derived actor and message types
+	unordered_set<const StructDecl *> actorStructDecls;
+	unordered_set<const StructDecl *> messageStructDecls;
+	FwdDeclTable forwardDecls;
+
+	// for storing through the passes
+	// these are populated with various important struct decls
+	const StructDecl * requestDeclPtr = nullptr;
+	const EnumDecl * allocationDeclPtr = nullptr;
+	const StructDecl * actorDeclPtr = nullptr;
+	const StructDecl * msgDeclPtr = nullptr;
+
+	// double pointer to modify local ptrs above
+	const StructDecl ** requestDecl = &requestDeclPtr;
+	const EnumDecl ** allocationDecl = &allocationDeclPtr;
+	const StructDecl ** actorDecl = &actorDeclPtr;
+	const StructDecl ** msgDecl = &msgDeclPtr;
+
+	// first pass collects ptrs to allocation enum, request type, and generic receive fn typedef
+	// also populates maps of all derived actors and messages
+	Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
+		allocationDecl, actorDecl, msgDecl );
+
+	// check that we have found all the decls we need from <actor.hfa>, if not no need to run the rest of this pass
+	if ( !allocationDeclPtr || !requestDeclPtr || !actorDeclPtr || !msgDeclPtr )
+		return;
+
+	// second pass locates all receive() routines that overload the generic receive fn
+	// it then generates the appropriate operator '|' send routines for the receive routines
+	Pass<GenFuncsCreateTables>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
+		allocationDecl, actorDecl, msgDecl, forwardDecls );
+
+	// The third pass forward declares operator '|' send routines
+	Pass<FwdDeclOperator>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
 }
-
 
 } // namespace Concurrency
Index: src/Concurrency/Corun.cpp
===================================================================
--- src/Concurrency/Corun.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Concurrency/Corun.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -26,274 +26,274 @@
 
 struct CorunKeyword : public WithDeclsToAdd<>, public WithStmtsToAdd<> {
-    UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
-    UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;
-    // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;
-    UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
-    
-    string coforArgName = "__CFA_cofor_lambda_arg";
-    string numProcsName = "__CFA_cofor_num_procs";
-    string currProcsName = "__CFA_cofor_curr_procs";
-    string thdArrName = "__CFA_cofor_thread_array";
-    string loopTempName = "__CFA_cofor_loop_temp";
-    
-
-    const StructDecl * runnerBlockDecl = nullptr;
-    const StructDecl * coforRunnerDecl = nullptr;
-
-    // Finds runner_block (corun task) and cofor_runner (cofor task) decls
-    void previsit( const StructDecl * decl ) {
-        if ( !decl->body ) {
-            return;
-        } else if ( "runner_block" == decl->name ) {
-            assert( !runnerBlockDecl );
-            runnerBlockDecl = decl;
-        } else if ( "cofor_runner" == decl->name ) {
-            assert( !coforRunnerDecl );
-            coforRunnerDecl = decl;
-        }
-    }
-
-    // codegen for cofor statements
-    Stmt * postvisit( const CoforStmt * stmt ) {
-        if ( !runnerBlockDecl || !coforRunnerDecl )
-            SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>" );
-
-        if ( stmt->inits.size() != 1 )
-            SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control" );
-
-        if ( !stmt->body )
-            return nullptr;
-
-        const CodeLocation & loc = stmt->location;
-        const string fnName = CoforFnNamer.newName();
-
-        CompoundStmt * body = new CompoundStmt( loc );
-
-        // push back cofor initializer to generated body
-        body->push_back( deepCopy( stmt->inits.at(0) ) );
-
-        CompoundStmt * fnBody = new CompoundStmt( loc );
-
-        const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());
-        if ( ! declStmtPtr )
-            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?" );
-
-        const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());
-        if ( ! declPtr )
-            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?" );
-
-        Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );
-
-        // Generates:
-        // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
-        fnBody->push_back( new DeclStmt( loc, 
-            new ObjectDecl( loc,
-                declPtr->name,
-                initType,
-                new SingleInit( loc,
-                    UntypedExpr::createDeref( loc,
-                        new CastExpr( loc, 
-                            new NameExpr( loc, coforArgName ), 
-                            new PointerType( initType ), ExplicitCast
-                        )
-                    )
-                )
-            )
-        ));
-
-        // push rest of cofor body into loop lambda
-        fnBody->push_back( deepCopy( stmt->body ) );
-
-        // Generates:
-        // void __CFA_cofor_lambda_() {
-        //    typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
-        //    stmt->body;
-        // }
-        Stmt * coforLambda = new DeclStmt( loc,
-            new FunctionDecl( loc,
-                fnName,                                             // name
-                {
-                    new ObjectDecl( loc,
-                        coforArgName,
-                        new ast::PointerType( new ast::VoidType() )
-                    )
-                },                                                  // params
-                {},                                                 // return
-                fnBody   // body
-            )
-        );
-        body->push_back( coforLambda );
-
-        // Generates:
-        // unsigned __CFA_cofor_num_procs = get_proc_count();
-        body->push_back( new DeclStmt( loc,
-                new ObjectDecl( loc,
-                    numProcsName,
-                    new BasicType( BasicKind::UnsignedInt ),
-                    new SingleInit( loc, 
-                        new UntypedExpr( loc,
-                            new NameExpr( loc, "get_proc_count" ),
-                            {}
-                        )
-                    )
-                )
-            )
-        );
-
-        // Generates:
-        // unsigned __CFA_cofor_curr_procs = 0;
-        body->push_back( new DeclStmt( loc,
-                new ObjectDecl( loc,
-                    currProcsName,
-                    new BasicType( BasicKind::UnsignedInt ),
-                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
-                )
-            )
-        );
-
-        // Generates:
-        // unsigned cofor_runner __CFA_cofor_thread_array[nprocs];
-        body->push_back( new DeclStmt( loc,
-                new ObjectDecl( loc,
-                    thdArrName,
-                    new ast::ArrayType(
-                        new StructInstType( coforRunnerDecl ),
-                        new NameExpr( loc, numProcsName ),
-                        ast::FixedLen,
-                        ast::DynamicDim
-                    )
-                )
-            )
-        );
-
-        // Generates:
-        // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );
-        body->push_back( new ExprStmt( loc,
-            new UntypedExpr( loc,
-                new NameExpr( loc, "start_runners" ),
-                {
-                    new NameExpr( loc, thdArrName ),
-                    new NameExpr( loc, numProcsName ),
-                    new NameExpr( loc, fnName )
-                }
-            )
-        ));
-
-        // Generates:
-        // typeof(initializer) * __CFA_cofor_loop_temp = malloc();
-        CompoundStmt * forLoopBody = new CompoundStmt( loc );
-        forLoopBody->push_back( new DeclStmt( loc,
-                new ObjectDecl( loc,
-                    loopTempName,
-                    new PointerType( initType ),
-                    new SingleInit( loc, 
-                        new UntypedExpr( loc,
-                            new NameExpr( loc, "malloc" ),
-                            {}
-                        )
-                    )
-                )
-            )
-        );
-
-        // Generates:
-        // *__CFA_cofor_loop_temp = initializer;
-        forLoopBody->push_back( new ExprStmt( loc,
-            UntypedExpr::createAssign( loc,
-                UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),
-                new NameExpr( loc, declPtr->name )
-            )
-        ));
-
-        // Generates:
-        // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,
-        //     __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );
-        forLoopBody->push_back( new ExprStmt( loc,
-            new UntypedExpr( loc,
-                new NameExpr( loc, "send_work" ),
-                {
-                    new NameExpr( loc, thdArrName ),
-                    new NameExpr( loc, numProcsName ),
-                    new NameExpr( loc, currProcsName ),
-                    new NameExpr( loc, loopTempName )
-                }
-            )
-        ));
-
-        body->push_back( new ForStmt( loc,
-            {},
-            deepCopy( stmt->cond ),
-            deepCopy( stmt->inc ),
-            forLoopBody
-        ));
-
-        // Generates:
-        // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );
-        body->push_back( new ExprStmt( loc,
-            new UntypedExpr( loc,
-                new NameExpr( loc, "end_runners" ),
-                {
-                    new NameExpr( loc, thdArrName ),
-                    new NameExpr( loc, numProcsName )
-                }
-            )
-        ));
-
-        return body;
-    }
-
-    // codegen for corun statements
-    Stmt * postvisit( const CorunStmt * stmt ) {
-        if ( !runnerBlockDecl || !coforRunnerDecl )
-            SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>" );
-
-        if ( !stmt->stmt )
-            return nullptr;
-
-        const CodeLocation & loc = stmt->location;
-        const string fnName = CorunFnNamer.newName();
-        const string objName = RunnerBlockNamer.newName();
-
-        // Generates:
-        // void __CFA_corun_lambda_() { ... stmt->stmt ... }
-        Stmt * runnerLambda = new DeclStmt( loc,
-            new FunctionDecl( loc,
-                fnName,                                             // name
-                {},                                                 // params
-                {},                                                 // return
-                new CompoundStmt( loc, { deepCopy(stmt->stmt) } )   // body
-            )
-        );
-
-        // Generates:
-        // runner_block __CFA_corun_block_;
-        Stmt * objDecl = new DeclStmt( loc,
-            new ObjectDecl( loc,
-                objName,
-                new StructInstType( runnerBlockDecl )
-            )
-        );
-
-        // Generates:
-        // __CFA_corun_block_{ __CFA_corun_lambda_ };
-        Stmt * threadStart = new ExprStmt( loc,
-            new UntypedExpr ( loc,
-                new NameExpr( loc, "?{}" ),
-                {
-                    new NameExpr( loc, objName ),
-                    new NameExpr( loc, fnName )
-                }
-            )
-        );
-
-        stmtsToAddBefore.push_back( runnerLambda );
-        stmtsToAddBefore.push_back( objDecl );
-
-        return threadStart;
-    }
+	UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
+	UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;
+	// UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;
+	UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
+
+	string coforArgName = "__CFA_cofor_lambda_arg";
+	string numProcsName = "__CFA_cofor_num_procs";
+	string currProcsName = "__CFA_cofor_curr_procs";
+	string thdArrName = "__CFA_cofor_thread_array";
+	string loopTempName = "__CFA_cofor_loop_temp";
+
+
+	const StructDecl * runnerBlockDecl = nullptr;
+	const StructDecl * coforRunnerDecl = nullptr;
+
+	// Finds runner_block (corun task) and cofor_runner (cofor task) decls
+	void previsit( const StructDecl * decl ) {
+		if ( !decl->body ) {
+			return;
+		} else if ( "runner_block" == decl->name ) {
+			assert( !runnerBlockDecl );
+			runnerBlockDecl = decl;
+		} else if ( "cofor_runner" == decl->name ) {
+			assert( !coforRunnerDecl );
+			coforRunnerDecl = decl;
+		}
+	}
+
+	// codegen for cofor statements
+	Stmt * postvisit( const CoforStmt * stmt ) {
+		if ( !runnerBlockDecl || !coforRunnerDecl )
+			SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>" );
+
+		if ( stmt->inits.size() != 1 )
+			SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control" );
+
+		if ( !stmt->body )
+			return nullptr;
+
+		const CodeLocation & loc = stmt->location;
+		const string fnName = CoforFnNamer.newName();
+
+		CompoundStmt * body = new CompoundStmt( loc );
+
+		// push back cofor initializer to generated body
+		body->push_back( deepCopy( stmt->inits.at(0) ) );
+
+		CompoundStmt * fnBody = new CompoundStmt( loc );
+
+		const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());
+		if ( ! declStmtPtr )
+			SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?" );
+
+		const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());
+		if ( ! declPtr )
+			SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?" );
+
+		Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );
+
+		// Generates:
+		// typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
+		fnBody->push_back( new DeclStmt( loc,
+			new ObjectDecl( loc,
+				declPtr->name,
+				initType,
+				new SingleInit( loc,
+					UntypedExpr::createDeref( loc,
+						new CastExpr( loc,
+							new NameExpr( loc, coforArgName ),
+							new PointerType( initType ), ExplicitCast
+						)
+					)
+				)
+			)
+		));
+
+		// push rest of cofor body into loop lambda
+		fnBody->push_back( deepCopy( stmt->body ) );
+
+		// Generates:
+		// void __CFA_cofor_lambda_() {
+		//    typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
+		//    stmt->body;
+		// }
+		Stmt * coforLambda = new DeclStmt( loc,
+			new FunctionDecl( loc,
+				fnName,                                             // name
+				{
+					new ObjectDecl( loc,
+						coforArgName,
+						new ast::PointerType( new ast::VoidType() )
+					)
+				},                                                  // params
+				{},                                                 // return
+				fnBody   // body
+			)
+		);
+		body->push_back( coforLambda );
+
+		// Generates:
+		// unsigned __CFA_cofor_num_procs = get_proc_count();
+		body->push_back( new DeclStmt( loc,
+				new ObjectDecl( loc,
+					numProcsName,
+					new BasicType( BasicKind::UnsignedInt ),
+					new SingleInit( loc,
+						new UntypedExpr( loc,
+							new NameExpr( loc, "get_proc_count" ),
+							{}
+						)
+					)
+				)
+			)
+		);
+
+		// Generates:
+		// unsigned __CFA_cofor_curr_procs = 0;
+		body->push_back( new DeclStmt( loc,
+				new ObjectDecl( loc,
+					currProcsName,
+					new BasicType( BasicKind::UnsignedInt ),
+					new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
+				)
+			)
+		);
+
+		// Generates:
+		// unsigned cofor_runner __CFA_cofor_thread_array[nprocs];
+		body->push_back( new DeclStmt( loc,
+				new ObjectDecl( loc,
+					thdArrName,
+					new ast::ArrayType(
+						new StructInstType( coforRunnerDecl ),
+						new NameExpr( loc, numProcsName ),
+						ast::FixedLen,
+						ast::DynamicDim
+					)
+				)
+			)
+		);
+
+		// Generates:
+		// start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );
+		body->push_back( new ExprStmt( loc,
+			new UntypedExpr( loc,
+				new NameExpr( loc, "start_runners" ),
+				{
+					new NameExpr( loc, thdArrName ),
+					new NameExpr( loc, numProcsName ),
+					new NameExpr( loc, fnName )
+				}
+			)
+		));
+
+		// Generates:
+		// typeof(initializer) * __CFA_cofor_loop_temp = malloc();
+		CompoundStmt * forLoopBody = new CompoundStmt( loc );
+		forLoopBody->push_back( new DeclStmt( loc,
+				new ObjectDecl( loc,
+					loopTempName,
+					new PointerType( initType ),
+					new SingleInit( loc,
+						new UntypedExpr( loc,
+							new NameExpr( loc, "malloc" ),
+							{}
+						)
+					)
+				)
+			)
+		);
+
+		// Generates:
+		// *__CFA_cofor_loop_temp = initializer;
+		forLoopBody->push_back( new ExprStmt( loc,
+			UntypedExpr::createAssign( loc,
+				UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),
+				new NameExpr( loc, declPtr->name )
+			)
+		));
+
+		// Generates:
+		// send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,
+		//     __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );
+		forLoopBody->push_back( new ExprStmt( loc,
+			new UntypedExpr( loc,
+				new NameExpr( loc, "send_work" ),
+				{
+					new NameExpr( loc, thdArrName ),
+					new NameExpr( loc, numProcsName ),
+					new NameExpr( loc, currProcsName ),
+					new NameExpr( loc, loopTempName )
+				}
+			)
+		));
+
+		body->push_back( new ForStmt( loc,
+			{},
+			deepCopy( stmt->cond ),
+			deepCopy( stmt->inc ),
+			forLoopBody
+		));
+
+		// Generates:
+		// end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );
+		body->push_back( new ExprStmt( loc,
+			new UntypedExpr( loc,
+				new NameExpr( loc, "end_runners" ),
+				{
+					new NameExpr( loc, thdArrName ),
+					new NameExpr( loc, numProcsName )
+				}
+			)
+		));
+
+		return body;
+	}
+
+	// codegen for corun statements
+	Stmt * postvisit( const CorunStmt * stmt ) {
+		if ( !runnerBlockDecl || !coforRunnerDecl )
+			SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>" );
+
+		if ( !stmt->stmt )
+			return nullptr;
+
+		const CodeLocation & loc = stmt->location;
+		const string fnName = CorunFnNamer.newName();
+		const string objName = RunnerBlockNamer.newName();
+
+		// Generates:
+		// void __CFA_corun_lambda_() { ... stmt->stmt ... }
+		Stmt * runnerLambda = new DeclStmt( loc,
+			new FunctionDecl( loc,
+				fnName,                                             // name
+				{},                                                 // params
+				{},                                                 // return
+				new CompoundStmt( loc, { deepCopy(stmt->stmt) } )   // body
+			)
+		);
+
+		// Generates:
+		// runner_block __CFA_corun_block_;
+		Stmt * objDecl = new DeclStmt( loc,
+			new ObjectDecl( loc,
+				objName,
+				new StructInstType( runnerBlockDecl )
+			)
+		);
+
+		// Generates:
+		// __CFA_corun_block_{ __CFA_corun_lambda_ };
+		Stmt * threadStart = new ExprStmt( loc,
+			new UntypedExpr ( loc,
+				new NameExpr( loc, "?{}" ),
+				{
+					new NameExpr( loc, objName ),
+					new NameExpr( loc, fnName )
+				}
+			)
+		);
+
+		stmtsToAddBefore.push_back( runnerLambda );
+		stmtsToAddBefore.push_back( objDecl );
+
+		return threadStart;
+	}
 };
 
 void implementCorun( TranslationUnit & translationUnit ) {
-    Pass<CorunKeyword>::run( translationUnit );
+	Pass<CorunKeyword>::run( translationUnit );
 }
 
Index: src/Concurrency/Keywords.cpp
===================================================================
--- src/Concurrency/Keywords.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Concurrency/Keywords.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -991,5 +991,5 @@
 	ast::CompoundStmt * body =
 			new ast::CompoundStmt( stmt->location, { stmt->stmt } );
-	
+
 	return addStatements( body, stmt->mutexObjs );;
 }
@@ -1180,5 +1180,5 @@
 
 // generates a cast to the void ptr to the appropriate lock type and dereferences it before calling lock or unlock on it
-// used to undo the type erasure done by storing all the lock pointers as void 
+// used to undo the type erasure done by storing all the lock pointers as void
 ast::ExprStmt * MutexKeyword::genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param ) {
 	return new ast::ExprStmt( location,
@@ -1187,5 +1187,5 @@
 				ast::UntypedExpr::createDeref(
 					location,
-					new ast::CastExpr( location, 
+					new ast::CastExpr( location,
 						param,
 						new ast::PointerType( new ast::TypeofType( new ast::UntypedExpr(
@@ -1208,5 +1208,5 @@
 	//adds an if/elif clause for each lock to assign type from void ptr based on ptr address
 	for ( long unsigned int i = 0; i < args.size(); i++ ) {
-		
+
 		ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
 			new ast::NameExpr( location, "?==?" ), {
@@ -1216,10 +1216,10 @@
 		);
 
-		ast::IfStmt * currLockIf = new ast::IfStmt( 
+		ast::IfStmt * currLockIf = new ast::IfStmt(
 			location,
 			ifCond,
 			genVirtLockUnlockExpr( fnName, args.at(i), location, ast::deepCopy( thisParam ) )
 		);
-		
+
 		if ( i == 0 ) {
 			outerLockIf = currLockIf;
@@ -1235,9 +1235,9 @@
 
 void flattenTuple( const ast::UntypedTupleExpr * tuple, std::vector<ast::ptr<ast::Expr>> & output ) {
-    for ( auto & expr : tuple->exprs ) {
-        const ast::UntypedTupleExpr * innerTuple = dynamic_cast<const ast::UntypedTupleExpr *>(expr.get());
-        if ( innerTuple ) flattenTuple( innerTuple, output );
-        else output.emplace_back( ast::deepCopy( expr ));
-    }
+	for ( auto & expr : tuple->exprs ) {
+		const ast::UntypedTupleExpr * innerTuple = dynamic_cast<const ast::UntypedTupleExpr *>(expr.get());
+		if ( innerTuple ) flattenTuple( innerTuple, output );
+		else output.emplace_back( ast::deepCopy( expr ));
+	}
 }
 
@@ -1255,11 +1255,11 @@
 	// std::string unlockFnName = mutex_func_namer.newName();
 
-    // If any arguments to the mutex stmt are tuples, flatten them
-    std::vector<ast::ptr<ast::Expr>> flattenedArgs;
-    for ( auto & arg : args ) {
-        const ast::UntypedTupleExpr * tuple = dynamic_cast<const ast::UntypedTupleExpr *>(args.at(0).get());
-        if ( tuple ) flattenTuple( tuple, flattenedArgs );
-        else flattenedArgs.emplace_back( ast::deepCopy( arg ));
-    }
+	// If any arguments to the mutex stmt are tuples, flatten them
+	std::vector<ast::ptr<ast::Expr>> flattenedArgs;
+	for ( auto & arg : args ) {
+		const ast::UntypedTupleExpr * tuple = dynamic_cast<const ast::UntypedTupleExpr *>(args.at(0).get());
+		if ( tuple ) flattenTuple( tuple, flattenedArgs );
+		else flattenedArgs.emplace_back( ast::deepCopy( arg ));
+	}
 
 	// Make pointer to the monitors.
@@ -1302,5 +1302,5 @@
 	// adds a nested try stmt for each lock we are locking
 	for ( long unsigned int i = 0; i < flattenedArgs.size(); i++ ) {
-		ast::UntypedExpr * innerAccess = new ast::UntypedExpr( 
+		ast::UntypedExpr * innerAccess = new ast::UntypedExpr(
 			location,
 			new ast::NameExpr( location,"?[?]" ), {
@@ -1426,5 +1426,5 @@
 	// 	);
 
-	// 	ast::IfStmt * currLockIf = new ast::IfStmt( 
+	// 	ast::IfStmt * currLockIf = new ast::IfStmt(
 	// 		location,
 	// 		ast::deepCopy( ifCond ),
@@ -1432,10 +1432,10 @@
 	// 	);
 
-	// 	ast::IfStmt * currUnlockIf = new ast::IfStmt( 
+	// 	ast::IfStmt * currUnlockIf = new ast::IfStmt(
 	// 		location,
 	// 		ifCond,
 	// 		genVirtLockUnlockExpr( "unlock", args.at(i), location, ast::deepCopy( thisParam ) )
 	// 	);
-		
+
 	// 	if ( i == 0 ) {
 	// 		outerLockIf = currLockIf;
@@ -1450,5 +1450,5 @@
 	// 	lastUnlockIf = currUnlockIf;
 	// }
-	
+
 	// // add pointer typing if/elifs to body of routines
 	// lock_decl->stmts = new ast::CompoundStmt( location, { outerLockIf } );
Index: src/Concurrency/Waituntil.cpp
===================================================================
--- src/Concurrency/Waituntil.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Concurrency/Waituntil.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -31,7 +31,7 @@
 /* So this is what this pass dones:
 {
-    when ( condA ) waituntil( A ){ doA(); } 
-    or when ( condB ) waituntil( B ){ doB(); } 
-    and when ( condC ) waituntil( C ) { doC(); }
+	when ( condA ) waituntil( A ){ doA(); }
+	or when ( condB ) waituntil( B ){ doB(); }
+	and when ( condC ) waituntil( C ) { doC(); }
 }
 		 ||
@@ -42,89 +42,89 @@
 Generates these two routines:
 static inline bool is_full_sat_1( int * clause_statuses ) {
-    return clause_statuses[0] 
-        || clause_statuses[1]
-        && clause_statuses[2];
+	return clause_statuses[0]
+		|| clause_statuses[1]
+		&& clause_statuses[2];
 }
 
 static inline bool is_done_sat_1( int * clause_statuses ) {
-    return has_run(clause_statuses[0])
-        || has_run(clause_statuses[1])
-        && has_run(clause_statuses[2]);
+	return has_run(clause_statuses[0])
+		|| has_run(clause_statuses[1])
+		&& has_run(clause_statuses[2]);
 }
 
 Replaces the waituntil statement above with the following code:
 {
-    // used with atomic_dec/inc to get binary semaphore behaviour
-    int park_counter = 0;
-
-    // status (one for each clause)
-    int clause_statuses[3] = { 0 };
-
-    bool whenA = condA;
-    bool whenB = condB;
-    bool whenC = condC;
-
-    if ( !whenB ) clause_statuses[1] = __SELECT_RUN;
-    if ( !whenC ) clause_statuses[2] = __SELECT_RUN;
-
-    // some other conditional settors for clause_statuses are set here, see genSubtreeAssign and related routines
-
-    // three blocks
-    // for each block, create, setup, then register select_node
-    select_node clause1;
-    select_node clause2;
-    select_node clause3;
-
-    try {
-        if ( whenA ) { register_select(A, clause1); setup_clause( clause1, &clause_statuses[0], &park_counter ); }
-        ... repeat ^ for B and C ... 
-
-        // if else clause is defined a separate branch can occur here to set initial values, see genWhenStateConditions
-
-        // loop & park until done
-        while( !is_full_sat_1( clause_statuses ) ) {
-            
-            // binary sem P();
-            if ( __atomic_sub_fetch( &park_counter, 1, __ATOMIC_SEQ_CST) < 0 )
-                park();
-            
-            // execute any blocks available with status set to 0
-            for ( int i = 0; i < 3; i++ ) {
-                if (clause_statuses[i] == __SELECT_SAT) {
-                    switch (i) {
-                        case 0:
-                            try {
-                                    on_selected( A, clause1 );
-                                    doA();
-                            }
-                            finally { clause_statuses[i] = __SELECT_RUN; unregister_select(A, clause1); }
-                            break;
-                        case 1:
-                            ... same gen as A but for B and clause2 ...
-                            break;
-                        case 2:
-                            ... same gen as A but for C and clause3 ...
-                            break;
-                    }
-                }
-            }
-        }
-
-        // ensure that the blocks that triggered is_full_sat_1 are run
-        // by running every un-run block that is SAT from the start until
-        // the predicate is SAT when considering RUN status = true
-        for ( int i = 0; i < 3; i++ ) {
-            if (is_done_sat_1( clause_statuses )) break;
-            if (clause_statuses[i] == __SELECT_SAT)
-                ... Same if body here as in loop above ...
-        }
-    } finally {
-        // the unregister and on_selected calls are needed to support primitives where the acquire has side effects
-        // so the corresponding block MUST be run for those primitives to not lose state (example is channels)
-        if ( !has_run(clause_statuses[0]) && whenA && unregister_select(A, clause1) )
-            on_selected( A, clause1 )
-            doA(); 
-        ... repeat if above for B and C ...
-    }
+	// used with atomic_dec/inc to get binary semaphore behaviour
+	int park_counter = 0;
+
+	// status (one for each clause)
+	int clause_statuses[3] = { 0 };
+
+	bool whenA = condA;
+	bool whenB = condB;
+	bool whenC = condC;
+
+	if ( !whenB ) clause_statuses[1] = __SELECT_RUN;
+	if ( !whenC ) clause_statuses[2] = __SELECT_RUN;
+
+	// some other conditional settors for clause_statuses are set here, see genSubtreeAssign and related routines
+
+	// three blocks
+	// for each block, create, setup, then register select_node
+	select_node clause1;
+	select_node clause2;
+	select_node clause3;
+
+	try {
+		if ( whenA ) { register_select(A, clause1); setup_clause( clause1, &clause_statuses[0], &park_counter ); }
+		... repeat ^ for B and C ...
+
+		// if else clause is defined a separate branch can occur here to set initial values, see genWhenStateConditions
+
+		// loop & park until done
+		while( !is_full_sat_1( clause_statuses ) ) {
+
+			// binary sem P();
+			if ( __atomic_sub_fetch( &park_counter, 1, __ATOMIC_SEQ_CST) < 0 )
+				park();
+
+			// execute any blocks available with status set to 0
+			for ( int i = 0; i < 3; i++ ) {
+				if (clause_statuses[i] == __SELECT_SAT) {
+				    switch (i) {
+				        case 0:
+				            try {
+				                    on_selected( A, clause1 );
+				                    doA();
+				            }
+				            finally { clause_statuses[i] = __SELECT_RUN; unregister_select(A, clause1); }
+				            break;
+				        case 1:
+				            ... same gen as A but for B and clause2 ...
+				            break;
+				        case 2:
+				            ... same gen as A but for C and clause3 ...
+				            break;
+				    }
+				}
+			}
+		}
+
+		// ensure that the blocks that triggered is_full_sat_1 are run
+		// by running every un-run block that is SAT from the start until
+		// the predicate is SAT when considering RUN status = true
+		for ( int i = 0; i < 3; i++ ) {
+			if (is_done_sat_1( clause_statuses )) break;
+			if (clause_statuses[i] == __SELECT_SAT)
+				... Same if body here as in loop above ...
+		}
+	} finally {
+		// the unregister and on_selected calls are needed to support primitives where the acquire has side effects
+		// so the corresponding block MUST be run for those primitives to not lose state (example is channels)
+		if ( !has_run(clause_statuses[0]) && whenA && unregister_select(A, clause1) )
+			on_selected( A, clause1 )
+			doA();
+		... repeat if above for B and C ...
+	}
 }
 
@@ -134,63 +134,63 @@
 
 class GenerateWaitUntilCore final {
-    vector<FunctionDecl *> & satFns;
+	vector<FunctionDecl *> & satFns;
 	UniqueName namer_sat = "__is_full_sat_"s;
-    UniqueName namer_run = "__is_run_sat_"s;
+	UniqueName namer_run = "__is_run_sat_"s;
 	UniqueName namer_park = "__park_counter_"s;
 	UniqueName namer_status = "__clause_statuses_"s;
 	UniqueName namer_node = "__clause_"s;
-    UniqueName namer_target = "__clause_target_"s;
-    UniqueName namer_when = "__when_cond_"s;
-    UniqueName namer_label = "__waituntil_label_"s;
-
-    string idxName = "__CFA_clause_idx_";
-
-    struct ClauseData {
-        string nodeName;
-        string targetName;
-        string whenName;
-        int index;
-        string & statusName;
-        ClauseData( int index, string & statusName ) : index(index), statusName(statusName) {}
-    };
-
-    const StructDecl * selectNodeDecl = nullptr;
-
-    // This first set of routines are all used to do the complicated job of 
-    //    dealing with how to set predicate statuses with certain when_conds T/F
-    //    so that the when_cond == F effectively makes that clause "disappear"
-    void updateAmbiguousWhen( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool andBelow, bool orBelow );
-    void paintWhenTree( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool & andBelow, bool & orBelow );
-    bool paintWhenTree( WaitUntilStmt::ClauseNode * currNode );
-    void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs, int & index, bool parentAmbig, bool parentAnd );
-    void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs );
-    void updateWhenState( WaitUntilStmt::ClauseNode * currNode );
-    void genSubtreeAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, bool status, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
-    void genStatusAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
-    CompoundStmt * getStatusAssignment( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData );
-    Stmt * genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx );
-
-    // These routines are just code-gen helpers
-    void addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName );
-    void setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body );
-    CompoundStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName );
-    Expr * genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName );
-    CompoundStmt * genStmtBlock( const WhenClause * clause, const ClauseData * data );
-    Stmt * genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData );
-    Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData );
-    void genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName );
-    Stmt * recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName );
-    Stmt * buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data );
-    Stmt * genAllOr( const WaitUntilStmt * stmt );
+	UniqueName namer_target = "__clause_target_"s;
+	UniqueName namer_when = "__when_cond_"s;
+	UniqueName namer_label = "__waituntil_label_"s;
+
+	string idxName = "__CFA_clause_idx_";
+
+	struct ClauseData {
+		string nodeName;
+		string targetName;
+		string whenName;
+		int index;
+		string & statusName;
+		ClauseData( int index, string & statusName ) : index(index), statusName(statusName) {}
+	};
+
+	const StructDecl * selectNodeDecl = nullptr;
+
+	// This first set of routines are all used to do the complicated job of
+	//    dealing with how to set predicate statuses with certain when_conds T/F
+	//    so that the when_cond == F effectively makes that clause "disappear"
+	void updateAmbiguousWhen( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool andBelow, bool orBelow );
+	void paintWhenTree( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool & andBelow, bool & orBelow );
+	bool paintWhenTree( WaitUntilStmt::ClauseNode * currNode );
+	void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs, int & index, bool parentAmbig, bool parentAnd );
+	void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs );
+	void updateWhenState( WaitUntilStmt::ClauseNode * currNode );
+	void genSubtreeAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, bool status, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
+	void genStatusAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
+	CompoundStmt * getStatusAssignment( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData );
+	Stmt * genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx );
+
+	// These routines are just code-gen helpers
+	void addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName );
+	void setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body );
+	CompoundStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName );
+	Expr * genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName );
+	CompoundStmt * genStmtBlock( const WhenClause * clause, const ClauseData * data );
+	Stmt * genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData );
+	Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData );
+	void genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName );
+	Stmt * recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName );
+	Stmt * buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data );
+	Stmt * genAllOr( const WaitUntilStmt * stmt );
 
   public:
-    void previsit( const StructDecl * decl );
+	void previsit( const StructDecl * decl );
 	Stmt * postvisit( const WaitUntilStmt * stmt );
-    GenerateWaitUntilCore( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
+	GenerateWaitUntilCore( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
 };
 
 // Finds select_node decl
 void GenerateWaitUntilCore::previsit( const StructDecl * decl ) {
-    if ( !decl->body ) {
+	if ( !decl->body ) {
 		return;
 	} else if ( "select_node" == decl->name ) {
@@ -201,9 +201,9 @@
 
 void GenerateWaitUntilCore::updateAmbiguousWhen( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool andBelow, bool orBelow ) {
-    // all children when-ambiguous
-    if ( currNode->left->ambiguousWhen && currNode->right->ambiguousWhen )
-        // true iff an ancestor/descendant has a different operation
-        currNode->ambiguousWhen = (orAbove || orBelow) && (andBelow || andAbove);
-    // ambiguousWhen is initially false so theres no need to set it here
+	// all children when-ambiguous
+	if ( currNode->left->ambiguousWhen && currNode->right->ambiguousWhen )
+		// true iff an ancestor/descendant has a different operation
+		currNode->ambiguousWhen = (orAbove || orBelow) && (andBelow || andAbove);
+	// ambiguousWhen is initially false so theres no need to set it here
 }
 
@@ -215,36 +215,36 @@
 // - All of its descendent clauses are optional, i.e. they have a when_cond defined on the WhenClause
 void GenerateWaitUntilCore::paintWhenTree( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool & andBelow, bool & orBelow ) {
-    bool aBelow = false; // updated by child nodes
-    bool oBelow = false; // updated by child nodes
-    switch (currNode->op) {
-        case WaitUntilStmt::ClauseNode::AND:
-            paintWhenTree( currNode->left, true, orAbove, aBelow, oBelow );
-            paintWhenTree( currNode->right, true, orAbove, aBelow, oBelow );
-
-            // update currNode's when flag based on conditions listed in fn signature comment above
-            updateAmbiguousWhen(currNode, true, orAbove, aBelow, oBelow );
-
-            // set return flags to tell parents which decendant ops have been seen
-            andBelow = true;
-            orBelow = oBelow;
-            return;
-        case WaitUntilStmt::ClauseNode::OR:
-            paintWhenTree( currNode->left, andAbove, true, aBelow, oBelow );
-            paintWhenTree( currNode->right, andAbove, true, aBelow, oBelow );
-
-            // update currNode's when flag based on conditions listed in fn signature comment above
-            updateAmbiguousWhen(currNode, andAbove, true, aBelow, oBelow );
-
-            // set return flags to tell parents which decendant ops have been seen
-            andBelow = aBelow;
-            orBelow = true;
-            return;
-        case WaitUntilStmt::ClauseNode::LEAF:
-            if ( currNode->leaf->when_cond )
-                currNode->ambiguousWhen = true;
-            return;
-        default:
-            assertf(false, "Unreachable waituntil clause node type. How did you get here???");
-    }
+	bool aBelow = false; // updated by child nodes
+	bool oBelow = false; // updated by child nodes
+	switch (currNode->op) {
+		case WaitUntilStmt::ClauseNode::AND:
+			paintWhenTree( currNode->left, true, orAbove, aBelow, oBelow );
+			paintWhenTree( currNode->right, true, orAbove, aBelow, oBelow );
+
+			// update currNode's when flag based on conditions listed in fn signature comment above
+			updateAmbiguousWhen(currNode, true, orAbove, aBelow, oBelow );
+
+			// set return flags to tell parents which decendant ops have been seen
+			andBelow = true;
+			orBelow = oBelow;
+			return;
+		case WaitUntilStmt::ClauseNode::OR:
+			paintWhenTree( currNode->left, andAbove, true, aBelow, oBelow );
+			paintWhenTree( currNode->right, andAbove, true, aBelow, oBelow );
+
+			// update currNode's when flag based on conditions listed in fn signature comment above
+			updateAmbiguousWhen(currNode, andAbove, true, aBelow, oBelow );
+
+			// set return flags to tell parents which decendant ops have been seen
+			andBelow = aBelow;
+			orBelow = true;
+			return;
+		case WaitUntilStmt::ClauseNode::LEAF:
+			if ( currNode->leaf->when_cond )
+				currNode->ambiguousWhen = true;
+			return;
+		default:
+			assertf(false, "Unreachable waituntil clause node type. How did you get here???");
+	}
 }
 
@@ -252,18 +252,18 @@
 // returns true if entire tree is OR's (special case)
 bool GenerateWaitUntilCore::paintWhenTree( WaitUntilStmt::ClauseNode * currNode ) {
-    bool aBelow = false, oBelow = false; // unused by initial call
-    paintWhenTree( currNode, false, false, aBelow, oBelow );
-    return !aBelow;
+	bool aBelow = false, oBelow = false; // unused by initial call
+	paintWhenTree( currNode, false, false, aBelow, oBelow );
+	return !aBelow;
 }
 
 // Helper: returns Expr that represents arrName[index]
 Expr * genArrAccessExpr( const CodeLocation & loc, int index, string arrName ) {
-    return new UntypedExpr ( loc, 
-        new NameExpr( loc, "?[?]" ),
-        {
-            new NameExpr( loc, arrName ),
-            ConstantExpr::from_int( loc, index )
-        }
-    );
+	return new UntypedExpr ( loc,
+		new NameExpr( loc, "?[?]" ),
+		{
+			new NameExpr( loc, arrName ),
+			ConstantExpr::from_int( loc, index )
+		}
+	);
 }
 
@@ -273,35 +273,35 @@
 // - updates LEAF nodes to be when-ambiguous if their direct parent is when-ambiguous.
 void GenerateWaitUntilCore::collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs, int & index, bool parentAmbig, bool parentAnd ) {
-    switch (currNode->op) {
-        case WaitUntilStmt::ClauseNode::AND:
-            collectWhens( currNode->left, ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
-            collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
-            return;
-        case WaitUntilStmt::ClauseNode::OR:
-            collectWhens( currNode->left,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
-            collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
-            return;
-        case WaitUntilStmt::ClauseNode::LEAF:
-            if ( parentAmbig ) {
-                ambigIdxs.push_back(make_pair(index, currNode));
-            }
-            if ( parentAnd && currNode->leaf->when_cond ) {
-                currNode->childOfAnd = true;
-                andIdxs.push_back(index);
-            }
-            index++;
-            return;
-        default:
-            assertf(false, "Unreachable waituntil clause node type. How did you get here???");
-    }
+	switch (currNode->op) {
+		case WaitUntilStmt::ClauseNode::AND:
+			collectWhens( currNode->left, ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
+			collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
+			return;
+		case WaitUntilStmt::ClauseNode::OR:
+			collectWhens( currNode->left,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
+			collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
+			return;
+		case WaitUntilStmt::ClauseNode::LEAF:
+			if ( parentAmbig ) {
+				ambigIdxs.push_back(make_pair(index, currNode));
+			}
+			if ( parentAnd && currNode->leaf->when_cond ) {
+				currNode->childOfAnd = true;
+				andIdxs.push_back(index);
+			}
+			index++;
+			return;
+		default:
+			assertf(false, "Unreachable waituntil clause node type. How did you get here???");
+	}
 }
 
 // overloaded wrapper for collectWhens that sets initial values
 void GenerateWaitUntilCore::collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs ) {
-    int idx = 0;
-    collectWhens( currNode, ambigIdxs, andIdxs, idx, false, false );
-}
-
-// recursively updates ClauseNode whenState on internal nodes so that next pass can see which 
+	int idx = 0;
+	collectWhens( currNode, ambigIdxs, andIdxs, idx, false, false );
+}
+
+// recursively updates ClauseNode whenState on internal nodes so that next pass can see which
 //    subtrees are "turned off"
 // sets whenState = false iff both children have whenState == false.
@@ -309,11 +309,11 @@
 // since the ambiguous clauses were filtered in paintWhenTree we don't need to worry about that here
 void GenerateWaitUntilCore::updateWhenState( WaitUntilStmt::ClauseNode * currNode ) {
-    if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) return;
-    updateWhenState( currNode->left );
-    updateWhenState( currNode->right );
-    if ( !currNode->left->whenState && !currNode->right->whenState )
-        currNode->whenState = false;
-    else 
-        currNode->whenState = true;
+	if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) return;
+	updateWhenState( currNode->left );
+	updateWhenState( currNode->right );
+	if ( !currNode->left->whenState && !currNode->right->whenState )
+		currNode->whenState = false;
+	else
+		currNode->whenState = true;
 }
 
@@ -321,152 +321,152 @@
 // assumes that this will only be called on subtrees that are entirely whenState == false
 void GenerateWaitUntilCore::genSubtreeAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, bool status, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData ) {
-    if ( ( currNode->op == WaitUntilStmt::ClauseNode::AND && status )
-        || ( currNode->op == WaitUntilStmt::ClauseNode::OR && !status ) ) {
-        // need to recurse on both subtrees if && subtree needs to be true or || subtree needs to be false
-        genSubtreeAssign( stmt, currNode->left, status, idx, retStmt, clauseData );
-        genSubtreeAssign( stmt, currNode->right, status, idx, retStmt, clauseData );
-    } else if ( ( currNode->op == WaitUntilStmt::ClauseNode::OR && status )
-        || ( currNode->op == WaitUntilStmt::ClauseNode::AND && !status ) ) {
-        // only one subtree needs to evaluate to status if && subtree needs to be true or || subtree needs to be false
-        CompoundStmt * leftStmt = new CompoundStmt( stmt->location );
-        CompoundStmt * rightStmt = new CompoundStmt( stmt->location );
-
-        // only one side needs to evaluate to status so we recurse on both subtrees
-        //    but only keep the statements from the subtree with minimal statements
-        genSubtreeAssign( stmt, currNode->left, status, idx, leftStmt, clauseData );
-        genSubtreeAssign( stmt, currNode->right, status, idx, rightStmt, clauseData );
-        
-        // append minimal statements to retStmt
-        if ( leftStmt->kids.size() < rightStmt->kids.size() ) {
-            retStmt->kids.splice( retStmt->kids.end(), leftStmt->kids );
-        } else {
-            retStmt->kids.splice( retStmt->kids.end(), rightStmt->kids );
-        }
-        
-        delete leftStmt;
-        delete rightStmt;
-    } else if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) {
-        const CodeLocation & loc = stmt->location;
-        if ( status && !currNode->childOfAnd ) {
-            retStmt->push_back(
-                new ExprStmt( loc, 
-                    UntypedExpr::createAssign( loc,
-                        genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
-                        new NameExpr( loc, "__SELECT_RUN" )
-                    )
-                )
-            );
-        } else if ( !status && currNode->childOfAnd ) {
-            retStmt->push_back(
-                new ExprStmt( loc, 
-                    UntypedExpr::createAssign( loc,
-                        genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
-                        new NameExpr( loc, "__SELECT_UNSAT" )
-                    )
-                )
-            );
-        }
-
-        // No need to generate statements for the following cases since childOfAnd are always set to true
-        //    and !childOfAnd are always false
-        // - status && currNode->childOfAnd
-        // - !status && !currNode->childOfAnd
-        idx++;
-    }
+	if ( ( currNode->op == WaitUntilStmt::ClauseNode::AND && status )
+		|| ( currNode->op == WaitUntilStmt::ClauseNode::OR && !status ) ) {
+		// need to recurse on both subtrees if && subtree needs to be true or || subtree needs to be false
+		genSubtreeAssign( stmt, currNode->left, status, idx, retStmt, clauseData );
+		genSubtreeAssign( stmt, currNode->right, status, idx, retStmt, clauseData );
+	} else if ( ( currNode->op == WaitUntilStmt::ClauseNode::OR && status )
+		|| ( currNode->op == WaitUntilStmt::ClauseNode::AND && !status ) ) {
+		// only one subtree needs to evaluate to status if && subtree needs to be true or || subtree needs to be false
+		CompoundStmt * leftStmt = new CompoundStmt( stmt->location );
+		CompoundStmt * rightStmt = new CompoundStmt( stmt->location );
+
+		// only one side needs to evaluate to status so we recurse on both subtrees
+		//    but only keep the statements from the subtree with minimal statements
+		genSubtreeAssign( stmt, currNode->left, status, idx, leftStmt, clauseData );
+		genSubtreeAssign( stmt, currNode->right, status, idx, rightStmt, clauseData );
+
+		// append minimal statements to retStmt
+		if ( leftStmt->kids.size() < rightStmt->kids.size() ) {
+			retStmt->kids.splice( retStmt->kids.end(), leftStmt->kids );
+		} else {
+			retStmt->kids.splice( retStmt->kids.end(), rightStmt->kids );
+		}
+
+		delete leftStmt;
+		delete rightStmt;
+	} else if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) {
+		const CodeLocation & loc = stmt->location;
+		if ( status && !currNode->childOfAnd ) {
+			retStmt->push_back(
+				new ExprStmt( loc,
+				    UntypedExpr::createAssign( loc,
+				        genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
+				        new NameExpr( loc, "__SELECT_RUN" )
+				    )
+				)
+			);
+		} else if ( !status && currNode->childOfAnd ) {
+			retStmt->push_back(
+				new ExprStmt( loc,
+				    UntypedExpr::createAssign( loc,
+				        genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
+				        new NameExpr( loc, "__SELECT_UNSAT" )
+				    )
+				)
+			);
+		}
+
+		// No need to generate statements for the following cases since childOfAnd are always set to true
+		//    and !childOfAnd are always false
+		// - status && currNode->childOfAnd
+		// - !status && !currNode->childOfAnd
+		idx++;
+	}
 }
 
 void GenerateWaitUntilCore::genStatusAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData ) {
-    switch (currNode->op) {
-        case WaitUntilStmt::ClauseNode::AND:
-            // check which subtrees have all whenState == false (disabled)
-            if (!currNode->left->whenState && !currNode->right->whenState) {
-                // this case can only occur when whole tree is disabled since otherwise 
-                //    genStatusAssign( ... ) isn't called on nodes with whenState == false
-                assert( !currNode->whenState ); // paranoidWWW
-                // whole tree disabled so pass true so that select is SAT vacuously
-                genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
-            } else if ( !currNode->left->whenState ) {
-                // pass true since x && true === x
-                genSubtreeAssign( stmt, currNode->left, true, idx, retStmt, clauseData );
-                genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
-            } else if ( !currNode->right->whenState ) {
-                genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
-                genSubtreeAssign( stmt, currNode->right, true, idx, retStmt, clauseData );
-            } else { 
-                // if no children with whenState == false recurse normally via break
-                break;
-            }
-            return;
-        case WaitUntilStmt::ClauseNode::OR:
-            if (!currNode->left->whenState && !currNode->right->whenState) {
-                assert( !currNode->whenState ); // paranoid
-                genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
-            } else if ( !currNode->left->whenState ) {
-                // pass false since x || false === x
-                genSubtreeAssign( stmt, currNode->left, false, idx, retStmt, clauseData );
-                genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
-            } else if ( !currNode->right->whenState ) {
-                genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
-                genSubtreeAssign( stmt, currNode->right, false, idx, retStmt, clauseData );
-            } else { 
-                break;
-            }
-            return;
-        case WaitUntilStmt::ClauseNode::LEAF:
-            idx++;
-            return;
-        default:
-            assertf(false, "Unreachable waituntil clause node type. How did you get here???");
-    }
-    genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
-    genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
+	switch (currNode->op) {
+		case WaitUntilStmt::ClauseNode::AND:
+			// check which subtrees have all whenState == false (disabled)
+			if (!currNode->left->whenState && !currNode->right->whenState) {
+				// this case can only occur when whole tree is disabled since otherwise
+				//    genStatusAssign( ... ) isn't called on nodes with whenState == false
+				assert( !currNode->whenState ); // paranoidWWW
+				// whole tree disabled so pass true so that select is SAT vacuously
+				genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
+			} else if ( !currNode->left->whenState ) {
+				// pass true since x && true === x
+				genSubtreeAssign( stmt, currNode->left, true, idx, retStmt, clauseData );
+				genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
+			} else if ( !currNode->right->whenState ) {
+				genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
+				genSubtreeAssign( stmt, currNode->right, true, idx, retStmt, clauseData );
+			} else {
+				// if no children with whenState == false recurse normally via break
+				break;
+			}
+			return;
+		case WaitUntilStmt::ClauseNode::OR:
+			if (!currNode->left->whenState && !currNode->right->whenState) {
+				assert( !currNode->whenState ); // paranoid
+				genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
+			} else if ( !currNode->left->whenState ) {
+				// pass false since x || false === x
+				genSubtreeAssign( stmt, currNode->left, false, idx, retStmt, clauseData );
+				genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
+			} else if ( !currNode->right->whenState ) {
+				genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
+				genSubtreeAssign( stmt, currNode->right, false, idx, retStmt, clauseData );
+			} else {
+				break;
+			}
+			return;
+		case WaitUntilStmt::ClauseNode::LEAF:
+			idx++;
+			return;
+		default:
+			assertf(false, "Unreachable waituntil clause node type. How did you get here???");
+	}
+	genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
+	genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
 }
 
 // generates a minimal set of assignments for status arr based on which whens are toggled on/off
 CompoundStmt * GenerateWaitUntilCore::getStatusAssignment( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData ) {
-    updateWhenState( stmt->predicateTree );
-    CompoundStmt * retval = new CompoundStmt( stmt->location );
-    int idx = 0;
-    genStatusAssign( stmt, stmt->predicateTree, idx, retval, clauseData );
-    return retval;
+	updateWhenState( stmt->predicateTree );
+	CompoundStmt * retval = new CompoundStmt( stmt->location );
+	int idx = 0;
+	genStatusAssign( stmt, stmt->predicateTree, idx, retval, clauseData );
+	return retval;
 }
 
 // generates nested if/elses for all possible assignments of ambiguous when_conds
 // exponential size of code gen but linear runtime O(n), where n is number of ambiguous whens()
-Stmt * GenerateWaitUntilCore::genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, 
-    vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx ) {
-    // I hate C++ sometimes, using vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type for size() comparison seems silly.
-    //    Why is size_type parameterized on the type stored in the vector?????
-
-    const CodeLocation & loc = stmt->location;
-    int clauseIdx = ambigClauses.at(ambigIdx).first;
-    WaitUntilStmt::ClauseNode * currNode = ambigClauses.at(ambigIdx).second;
-    Stmt * thenStmt;
-    Stmt * elseStmt;
-    
-    if ( ambigIdx == ambigClauses.size() - 1 ) { // base case
-        currNode->whenState = true;
-        thenStmt = getStatusAssignment( stmt, clauseData );
-        currNode->whenState = false;
-        elseStmt = getStatusAssignment( stmt, clauseData );
-    } else {
-        // recurse both with when enabled and disabled to generate all possible cases
-        currNode->whenState = true;
-        thenStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
-        currNode->whenState = false;
-        elseStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
-    }
-
-    // insert first recursion result in if ( __when_cond_ ) { ... }
-    // insert second recursion result in else { ... }
-    return new CompoundStmt ( loc,
-        {
-            new IfStmt( loc,
-                new NameExpr( loc, clauseData.at(clauseIdx)->whenName ),
-                thenStmt,
-                elseStmt
-            )
-        }
-    );
+Stmt * GenerateWaitUntilCore::genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData,
+	vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx ) {
+	// I hate C++ sometimes, using vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type for size() comparison seems silly.
+	//    Why is size_type parameterized on the type stored in the vector?????
+
+	const CodeLocation & loc = stmt->location;
+	int clauseIdx = ambigClauses.at(ambigIdx).first;
+	WaitUntilStmt::ClauseNode * currNode = ambigClauses.at(ambigIdx).second;
+	Stmt * thenStmt;
+	Stmt * elseStmt;
+
+	if ( ambigIdx == ambigClauses.size() - 1 ) { // base case
+		currNode->whenState = true;
+		thenStmt = getStatusAssignment( stmt, clauseData );
+		currNode->whenState = false;
+		elseStmt = getStatusAssignment( stmt, clauseData );
+	} else {
+		// recurse both with when enabled and disabled to generate all possible cases
+		currNode->whenState = true;
+		thenStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
+		currNode->whenState = false;
+		elseStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
+	}
+
+	// insert first recursion result in if ( __when_cond_ ) { ... }
+	// insert second recursion result in else { ... }
+	return new CompoundStmt ( loc,
+		{
+			new IfStmt( loc,
+				new NameExpr( loc, clauseData.at(clauseIdx)->whenName ),
+				thenStmt,
+				elseStmt
+			)
+		}
+	);
 }
 
@@ -478,13 +478,13 @@
 // mutates index to be index + 1
 Expr * genSatExpr( const CodeLocation & loc, int & index ) {
-    return genArrAccessExpr( loc, index++, "clause_statuses" );
+	return genArrAccessExpr( loc, index++, "clause_statuses" );
 }
 
 // return Expr that represents has_run(clause_statuses[index])
 Expr * genRunExpr( const CodeLocation & loc, int & index ) {
-    return new UntypedExpr ( loc, 
-        new NameExpr( loc, "__CFA_has_clause_run" ),
-        { genSatExpr( loc, index ) }
-    );
+	return new UntypedExpr ( loc,
+		new NameExpr( loc, "__CFA_has_clause_run" ),
+		{ genSatExpr( loc, index ) }
+	);
 }
 
@@ -492,32 +492,32 @@
 // the predicate expr used inside the predicate functions
 Expr * genPredExpr( const CodeLocation & loc, WaitUntilStmt::ClauseNode * currNode, int & idx, GenLeafExpr genLeaf ) {
-    Expr * leftExpr, * rightExpr;
-    switch (currNode->op) {
-        case WaitUntilStmt::ClauseNode::AND:
-            leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
-            rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
-            return new LogicalExpr( loc, 
-                new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
-                new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ), 
-                LogicalFlag::AndExpr 
-            );
-            break;
-        case WaitUntilStmt::ClauseNode::OR:
-            leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
-            rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
-            return new LogicalExpr( loc,
-                new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
-                new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ), 
-                LogicalFlag::OrExpr );
-            break;
-        case WaitUntilStmt::ClauseNode::LEAF:
-            return genLeaf( loc, idx );
-            break;
-        default:
-            assertf(false, "Unreachable waituntil clause node type. How did you get here???");\
-            return nullptr;
-            break;
-    }
-    return nullptr;
+	Expr * leftExpr, * rightExpr;
+	switch (currNode->op) {
+		case WaitUntilStmt::ClauseNode::AND:
+			leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
+			rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
+			return new LogicalExpr( loc,
+				new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
+				new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
+				LogicalFlag::AndExpr
+			);
+			break;
+		case WaitUntilStmt::ClauseNode::OR:
+			leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
+			rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
+			return new LogicalExpr( loc,
+				new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
+				new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
+				LogicalFlag::OrExpr );
+			break;
+		case WaitUntilStmt::ClauseNode::LEAF:
+			return genLeaf( loc, idx );
+			break;
+		default:
+			assertf(false, "Unreachable waituntil clause node type. How did you get here???");\
+			return nullptr;
+			break;
+	}
+	return nullptr;
 }
 
@@ -526,19 +526,19 @@
 /* Ex:
 {
-    waituntil( A ){ doA(); } 
-    or waituntil( B ){ doB(); } 
-    and waituntil( C ) { doC(); }
+	waituntil( A ){ doA(); }
+	or waituntil( B ){ doB(); }
+	and waituntil( C ) { doC(); }
 }
 generates =>
 static inline bool is_full_sat_1( int * clause_statuses ) {
-    return clause_statuses[0] 
-        || clause_statuses[1]
-        && clause_statuses[2];
+	return clause_statuses[0]
+		|| clause_statuses[1]
+		&& clause_statuses[2];
 }
 
 static inline bool is_done_sat_1( int * clause_statuses ) {
-    return has_run(clause_statuses[0])
-        || has_run(clause_statuses[1])
-        && has_run(clause_statuses[2]);
+	return has_run(clause_statuses[0])
+		|| has_run(clause_statuses[1])
+		&& has_run(clause_statuses[2]);
 }
 */
@@ -546,36 +546,36 @@
 // predName and genLeaf determine if this generates an is_done or an is_full predicate
 FunctionDecl * buildPredicate( const WaitUntilStmt * stmt, GenLeafExpr genLeaf, string & predName ) {
-    int arrIdx = 0;
-    const CodeLocation & loc = stmt->location;
-    CompoundStmt * body = new CompoundStmt( loc );
-    body->push_back( new ReturnStmt( loc, genPredExpr( loc,  stmt->predicateTree, arrIdx, genLeaf ) ) );
-
-    return new FunctionDecl( loc,
-        predName,
-        {
-            new ObjectDecl( loc,
-                "clause_statuses",
-                new PointerType( new BasicType( BasicKind::LongUnsignedInt ) )
-            )
-        },
-        {
-            new ObjectDecl( loc,
-                "sat_ret",
-                new BasicType( BasicKind::Bool )
-            )
-        },
-        body,               // body
-        { Storage::Static },    // storage
-        Linkage::Cforall,       // linkage
-        {},                     // attributes
-        { Function::Inline }
-    );
+	int arrIdx = 0;
+	const CodeLocation & loc = stmt->location;
+	CompoundStmt * body = new CompoundStmt( loc );
+	body->push_back( new ReturnStmt( loc, genPredExpr( loc,  stmt->predicateTree, arrIdx, genLeaf ) ) );
+
+	return new FunctionDecl( loc,
+		predName,
+		{
+			new ObjectDecl( loc,
+				"clause_statuses",
+				new PointerType( new BasicType( BasicKind::LongUnsignedInt ) )
+			)
+		},
+		{
+			new ObjectDecl( loc,
+				"sat_ret",
+				new BasicType( BasicKind::Bool )
+			)
+		},
+		body,               // body
+		{ Storage::Static },    // storage
+		Linkage::Cforall,       // linkage
+		{},                     // attributes
+		{ Function::Inline }
+	);
 }
 
 // Creates is_done and is_full predicates
 void GenerateWaitUntilCore::addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName ) {
-    if ( !stmt->else_stmt || stmt->else_cond ) // don't need SAT predicate when else variation with no else_cond
-        satFns.push_back( Concurrency::buildPredicate( stmt, genSatExpr, satName ) ); 
-    satFns.push_back( Concurrency::buildPredicate( stmt, genRunExpr, runName ) );
+	if ( !stmt->else_stmt || stmt->else_cond ) // don't need SAT predicate when else variation with no else_cond
+		satFns.push_back( Concurrency::buildPredicate( stmt, genSatExpr, satName ) );
+	satFns.push_back( Concurrency::buildPredicate( stmt, genRunExpr, runName ) );
 }
 
@@ -585,232 +585,232 @@
 //      register_select(A, clause1);
 // }
-void GenerateWaitUntilCore::setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body ) {    
-    CompoundStmt * currBody = body;
-    const CodeLocation & loc = clause->location;
-
-    // If we have a when_cond make the initialization conditional
-    if ( clause->when_cond )
-        currBody = new CompoundStmt( loc );
-
-    // Generates: setup_clause( clause1, &clause_statuses[0], &park_counter );
-    currBody->push_back( new ExprStmt( loc,
-        new UntypedExpr ( loc,
-            new NameExpr( loc, "setup_clause" ),
-            {
-                new NameExpr( loc, data->nodeName ),
-                new AddressExpr( loc, genArrAccessExpr( loc, data->index, data->statusName ) ),
-                new AddressExpr( loc, new NameExpr( loc, pCountName ) )
-            }
-        )
-    ));
-
-    // Generates: register_select(A, clause1);
-    currBody->push_back( new ExprStmt( loc, genSelectTraitCall( clause, data, "register_select" ) ) );
-
-    // generates: if ( when_cond ) { ... currBody ... }
-    if ( clause->when_cond )
-        body->push_back( 
-            new IfStmt( loc,
-                new NameExpr( loc, data->whenName ),
-                currBody
-            )
-        );
+void GenerateWaitUntilCore::setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body ) {
+	CompoundStmt * currBody = body;
+	const CodeLocation & loc = clause->location;
+
+	// If we have a when_cond make the initialization conditional
+	if ( clause->when_cond )
+		currBody = new CompoundStmt( loc );
+
+	// Generates: setup_clause( clause1, &clause_statuses[0], &park_counter );
+	currBody->push_back( new ExprStmt( loc,
+		new UntypedExpr ( loc,
+			new NameExpr( loc, "setup_clause" ),
+			{
+				new NameExpr( loc, data->nodeName ),
+				new AddressExpr( loc, genArrAccessExpr( loc, data->index, data->statusName ) ),
+				new AddressExpr( loc, new NameExpr( loc, pCountName ) )
+			}
+		)
+	));
+
+	// Generates: register_select(A, clause1);
+	currBody->push_back( new ExprStmt( loc, genSelectTraitCall( clause, data, "register_select" ) ) );
+
+	// generates: if ( when_cond ) { ... currBody ... }
+	if ( clause->when_cond )
+		body->push_back(
+			new IfStmt( loc,
+				new NameExpr( loc, data->whenName ),
+				currBody
+			)
+		);
 }
 
 // Used to generate a call to one of the select trait routines
 Expr * GenerateWaitUntilCore::genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName ) {
-    const CodeLocation & loc = clause->location;
-    return new UntypedExpr ( loc,
-        new NameExpr( loc, fnName ),
-        {
-            new NameExpr( loc, data->targetName ),
-            new NameExpr( loc, data->nodeName )
-        }
-    );
+	const CodeLocation & loc = clause->location;
+	return new UntypedExpr ( loc,
+		new NameExpr( loc, fnName ),
+		{
+			new NameExpr( loc, data->targetName ),
+			new NameExpr( loc, data->nodeName )
+		}
+	);
 }
 
 // Generates:
-/* on_selected( target_1, node_1 ); ... corresponding body of target_1 ... 
+/* on_selected( target_1, node_1 ); ... corresponding body of target_1 ...
 */
 CompoundStmt * GenerateWaitUntilCore::genStmtBlock( const WhenClause * clause, const ClauseData * data ) {
-    const CodeLocation & cLoc = clause->location;
-    return new CompoundStmt( cLoc,
-        {
-            new IfStmt( cLoc,
-                genSelectTraitCall( clause, data, "on_selected" ),
-                ast::deepCopy( clause->stmt )
-            )
-        }
-    );
+	const CodeLocation & cLoc = clause->location;
+	return new CompoundStmt( cLoc,
+		{
+			new IfStmt( cLoc,
+				genSelectTraitCall( clause, data, "on_selected" ),
+				ast::deepCopy( clause->stmt )
+			)
+		}
+	);
 }
 
 // this routine generates and returns the following
 /*for ( int i = 0; i < numClauses; i++ ) {
-    if ( predName(clause_statuses) ) break;
-    if (clause_statuses[i] == __SELECT_SAT) {
-        switch (i) {
-            case 0:
-                try {
-                    on_selected( target1, clause1 );
-                    dotarget1stmt();
-                }
-                finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
-                break;
-            ...
-            case N:
-                ...
-                break;
-        }
-    }
+	if ( predName(clause_statuses) ) break;
+	if (clause_statuses[i] == __SELECT_SAT) {
+		switch (i) {
+			case 0:
+				try {
+				    on_selected( target1, clause1 );
+				    dotarget1stmt();
+				}
+				finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
+				break;
+			...
+			case N:
+				...
+				break;
+		}
+	}
 }*/
 CompoundStmt * GenerateWaitUntilCore::genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName ) {
-    CompoundStmt * ifBody = new CompoundStmt( stmt->location );
-    const CodeLocation & loc = stmt->location;
-
-    string switchLabel = namer_label.newName();
-
-    /* generates:
-    switch (i) {
-        case 0:
-            try {
-                on_selected( target1, clause1 );
-                dotarget1stmt();
-            }
-            finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
-            break;
-            ...
-        case N:
-            ...
-            break;
-    }*/
-    std::vector<ptr<CaseClause>> switchCases;
-    int idx = 0;
-    for ( const auto & clause: stmt->clauses ) {
-        const CodeLocation & cLoc = clause->location;
-        switchCases.push_back(
-            new CaseClause( cLoc,
-                ConstantExpr::from_int( cLoc, idx ),
-                {
-                    new CompoundStmt( cLoc,
-                        {
-                            new ast::TryStmt( cLoc,
-                                genStmtBlock( clause, clauseData.at(idx) ),
-                                {},
-                                new ast::FinallyClause( cLoc, 
-                                    new CompoundStmt( cLoc,
-                                        {
-                                            new ExprStmt( loc,
-                                                new UntypedExpr ( loc,
-                                                    new NameExpr( loc, "?=?" ),
-                                                    {
-                                                        new UntypedExpr ( loc, 
-                                                            new NameExpr( loc, "?[?]" ),
-                                                            {
-                                                                new NameExpr( loc, clauseData.at(0)->statusName ),
-                                                                new NameExpr( loc, idxName )
-                                                            }
-                                                        ),
-                                                        new NameExpr( loc, "__SELECT_RUN" )
-                                                    }
-                                                )
-                                            ),
-                                            new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select" ) )
-                                        }
-                                    )
-                                )
-                            ),
-                            new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc, switchLabel ) )
-                        }
-                    )
-                }
-            )
-        );
-        idx++;
-    }
-
-    ifBody->push_back(
-        new SwitchStmt( loc,
-            new NameExpr( loc, idxName ),
-            std::move( switchCases ),
-            { Label( loc, switchLabel ) }
-        )
-    );
-
-    // gens:
-    // if (clause_statuses[i] == __SELECT_SAT) {
-    //      ... ifBody  ...
-    // }
-    IfStmt * ifSwitch = new IfStmt( loc,
-        new UntypedExpr ( loc,
-            new NameExpr( loc, "?==?" ),
-            {
-                new UntypedExpr ( loc, 
-                    new NameExpr( loc, "?[?]" ),
-                    {
-                        new NameExpr( loc, clauseData.at(0)->statusName ),
-                        new NameExpr( loc, idxName )
-                    }
-                ),
-                new NameExpr( loc, "__SELECT_SAT" )
-            }
-        ),      // condition
-        ifBody  // body
-    );
-
-    string forLabel = namer_label.newName();
-
-    // we hoist init here so that this pass can happen after hoistdecls pass
-    return new CompoundStmt( loc,
-        {
-            new DeclStmt( loc,
-                new ObjectDecl( loc,
-                    idxName,
-                    new BasicType( BasicKind::SignedInt ),
-                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
-                )
-            ),
-            new ForStmt( loc,
-                {},  // inits
-                new UntypedExpr ( loc,
-                    new NameExpr( loc, "?<?" ),
-                    {
-                        new NameExpr( loc, idxName ),
-                        ConstantExpr::from_int( loc, stmt->clauses.size() )
-                    }
-                ),  // cond
-                new UntypedExpr ( loc,
-                    new NameExpr( loc, "?++" ),
-                    { new NameExpr( loc, idxName ) }
-                ),  // inc
-                new CompoundStmt( loc,
-                    {
-                        new IfStmt( loc,
-                            new UntypedExpr ( loc,
-                                new NameExpr( loc, predName ),
-                                { new NameExpr( loc, clauseData.at(0)->statusName ) }
-                            ),
-                            new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc, forLabel ) )
-                        ),
-                        ifSwitch
-                    }
-                ),   // body
-                { Label( loc, forLabel ) }
-            )
-        }
-    );
+	CompoundStmt * ifBody = new CompoundStmt( stmt->location );
+	const CodeLocation & loc = stmt->location;
+
+	string switchLabel = namer_label.newName();
+
+	/* generates:
+	switch (i) {
+		case 0:
+			try {
+				on_selected( target1, clause1 );
+				dotarget1stmt();
+			}
+			finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
+			break;
+			...
+		case N:
+			...
+			break;
+	}*/
+	std::vector<ptr<CaseClause>> switchCases;
+	int idx = 0;
+	for ( const auto & clause: stmt->clauses ) {
+		const CodeLocation & cLoc = clause->location;
+		switchCases.push_back(
+			new CaseClause( cLoc,
+				ConstantExpr::from_int( cLoc, idx ),
+				{
+				    new CompoundStmt( cLoc,
+				        {
+				            new ast::TryStmt( cLoc,
+				                genStmtBlock( clause, clauseData.at(idx) ),
+				                {},
+				                new ast::FinallyClause( cLoc,
+				                    new CompoundStmt( cLoc,
+				                        {
+				                            new ExprStmt( loc,
+				                                new UntypedExpr ( loc,
+				                                    new NameExpr( loc, "?=?" ),
+				                                    {
+				                                        new UntypedExpr ( loc,
+				                                            new NameExpr( loc, "?[?]" ),
+				                                            {
+				                                                new NameExpr( loc, clauseData.at(0)->statusName ),
+				                                                new NameExpr( loc, idxName )
+				                                            }
+				                                        ),
+				                                        new NameExpr( loc, "__SELECT_RUN" )
+				                                    }
+				                                )
+				                            ),
+				                            new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select" ) )
+				                        }
+				                    )
+				                )
+				            ),
+				            new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc, switchLabel ) )
+				        }
+				    )
+				}
+			)
+		);
+		idx++;
+	}
+
+	ifBody->push_back(
+		new SwitchStmt( loc,
+			new NameExpr( loc, idxName ),
+			std::move( switchCases ),
+			{ Label( loc, switchLabel ) }
+		)
+	);
+
+	// gens:
+	// if (clause_statuses[i] == __SELECT_SAT) {
+	//      ... ifBody  ...
+	// }
+	IfStmt * ifSwitch = new IfStmt( loc,
+		new UntypedExpr ( loc,
+			new NameExpr( loc, "?==?" ),
+			{
+				new UntypedExpr ( loc,
+				    new NameExpr( loc, "?[?]" ),
+				    {
+				        new NameExpr( loc, clauseData.at(0)->statusName ),
+				        new NameExpr( loc, idxName )
+				    }
+				),
+				new NameExpr( loc, "__SELECT_SAT" )
+			}
+		),      // condition
+		ifBody  // body
+	);
+
+	string forLabel = namer_label.newName();
+
+	// we hoist init here so that this pass can happen after hoistdecls pass
+	return new CompoundStmt( loc,
+		{
+			new DeclStmt( loc,
+				new ObjectDecl( loc,
+				    idxName,
+				    new BasicType( BasicKind::SignedInt ),
+				    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
+				)
+			),
+			new ForStmt( loc,
+				{},  // inits
+				new UntypedExpr ( loc,
+				    new NameExpr( loc, "?<?" ),
+				    {
+				        new NameExpr( loc, idxName ),
+				        ConstantExpr::from_int( loc, stmt->clauses.size() )
+				    }
+				),  // cond
+				new UntypedExpr ( loc,
+				    new NameExpr( loc, "?++" ),
+				    { new NameExpr( loc, idxName ) }
+				),  // inc
+				new CompoundStmt( loc,
+				    {
+				        new IfStmt( loc,
+				            new UntypedExpr ( loc,
+				                new NameExpr( loc, predName ),
+				                { new NameExpr( loc, clauseData.at(0)->statusName ) }
+				            ),
+				            new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc, forLabel ) )
+				        ),
+				        ifSwitch
+				    }
+				),   // body
+				{ Label( loc, forLabel ) }
+			)
+		}
+	);
 }
 
 // Generates: !is_full_sat_n() / !is_run_sat_n()
 Expr * genNotSatExpr( const WaitUntilStmt * stmt, string & satName, string & arrName ) {
-    const CodeLocation & loc = stmt->location;
-    return new UntypedExpr ( loc,
-        new NameExpr( loc, "!?" ),
-        {
-            new UntypedExpr ( loc,
-                new NameExpr( loc, satName ),
-                { new NameExpr( loc, arrName ) }
-            )
-        }
-    );
+	const CodeLocation & loc = stmt->location;
+	return new UntypedExpr ( loc,
+		new NameExpr( loc, "!?" ),
+		{
+			new UntypedExpr ( loc,
+				new NameExpr( loc, satName ),
+				{ new NameExpr( loc, arrName ) }
+			)
+		}
+	);
 }
 
@@ -819,40 +819,40 @@
 // If not enough have run to satisfy predicate after one pass then the else is run
 Stmt * GenerateWaitUntilCore::genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData ) {
-    return new CompoundStmt( stmt->else_stmt->location,
-        {
-            genStatusCheckFor( stmt, clauseData, runName ),
-            new IfStmt( stmt->else_stmt->location,
-                genNotSatExpr( stmt, runName, arrName ),
-                ast::deepCopy( stmt->else_stmt )
-            )
-        }
-    );
+	return new CompoundStmt( stmt->else_stmt->location,
+		{
+			genStatusCheckFor( stmt, clauseData, runName ),
+			new IfStmt( stmt->else_stmt->location,
+				genNotSatExpr( stmt, runName, arrName ),
+				ast::deepCopy( stmt->else_stmt )
+			)
+		}
+	);
 }
 
 Stmt * GenerateWaitUntilCore::genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData ) {
-    CompoundStmt * whileBody = new CompoundStmt( stmt->location );
-    const CodeLocation & loc = stmt->location;
-
-    // generates: __CFA_maybe_park( &park_counter );
-    whileBody->push_back(
-        new ExprStmt( loc,
-            new UntypedExpr ( loc,
-                new NameExpr( loc, "__CFA_maybe_park" ),
-                { new AddressExpr( loc, new NameExpr( loc, pCountName ) ) }
-            )
-        )
-    );
-
-    whileBody->push_back( genStatusCheckFor( stmt, clauseData, runName ) );
-
-    return new CompoundStmt( loc,
-        {
-            new WhileDoStmt( loc,
-                genNotSatExpr( stmt, runName, arrName ),
-                whileBody,  // body
-                {}          // no inits
-            )
-        }
-    );
+	CompoundStmt * whileBody = new CompoundStmt( stmt->location );
+	const CodeLocation & loc = stmt->location;
+
+	// generates: __CFA_maybe_park( &park_counter );
+	whileBody->push_back(
+		new ExprStmt( loc,
+			new UntypedExpr ( loc,
+				new NameExpr( loc, "__CFA_maybe_park" ),
+				{ new AddressExpr( loc, new NameExpr( loc, pCountName ) ) }
+			)
+		)
+	);
+
+	whileBody->push_back( genStatusCheckFor( stmt, clauseData, runName ) );
+
+	return new CompoundStmt( loc,
+		{
+			new WhileDoStmt( loc,
+				genNotSatExpr( stmt, runName, arrName ),
+				whileBody,  // body
+				{}          // no inits
+			)
+		}
+	);
 }
 
@@ -862,63 +862,63 @@
 // select_node clause1;
 void GenerateWaitUntilCore::genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName ) {
-    ClauseData * currClause;
-    for ( vector<ClauseData*>::size_type i = 0; i < stmt->clauses.size(); i++ ) {
-        currClause = new ClauseData( i, statusName );
-        currClause->nodeName = namer_node.newName();
-        currClause->targetName = namer_target.newName();
-        currClause->whenName = namer_when.newName();
-        clauseData.push_back(currClause);
-        const CodeLocation & cLoc = stmt->clauses.at(i)->location;
-
-        // typeof(target) & __clause_target_0 = target;
-        body->push_back(
-            new DeclStmt( cLoc,
-                new ObjectDecl( cLoc,
-                    currClause->targetName,
-                    new ReferenceType( 
-                        new TypeofType( new UntypedExpr( cLoc,
-                            new NameExpr( cLoc, "__CFA_select_get_type" ),
-                            { ast::deepCopy( stmt->clauses.at(i)->target ) }
-                        ))
-                    ),
-                    new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->target ) )
-                )
-            )
-        );
-
-        // bool __when_cond_0 = when_cond; // only generated if when_cond defined
-        if ( stmt->clauses.at(i)->when_cond )
-            body->push_back(
-                new DeclStmt( cLoc,
-                    new ObjectDecl( cLoc,
-                        currClause->whenName,
-                        new BasicType( BasicKind::Bool ),
-                        new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->when_cond ) )
-                    )
-                )
-            );
-        
-        // select_node clause1;
-        body->push_back(
-            new DeclStmt( cLoc,
-                new ObjectDecl( cLoc,
-                    currClause->nodeName,
-                    new StructInstType( selectNodeDecl )
-                )
-            )
-        );
-    }
-
-    if ( stmt->else_stmt && stmt->else_cond ) {
-        body->push_back(
-            new DeclStmt( stmt->else_cond->location,
-                new ObjectDecl( stmt->else_cond->location,
-                    elseWhenName,
-                    new BasicType( BasicKind::Bool ),
-                    new SingleInit( stmt->else_cond->location, ast::deepCopy( stmt->else_cond ) )
-                )
-            )
-        );
-    }
+	ClauseData * currClause;
+	for ( vector<ClauseData*>::size_type i = 0; i < stmt->clauses.size(); i++ ) {
+		currClause = new ClauseData( i, statusName );
+		currClause->nodeName = namer_node.newName();
+		currClause->targetName = namer_target.newName();
+		currClause->whenName = namer_when.newName();
+		clauseData.push_back(currClause);
+		const CodeLocation & cLoc = stmt->clauses.at(i)->location;
+
+		// typeof(target) & __clause_target_0 = target;
+		body->push_back(
+			new DeclStmt( cLoc,
+				new ObjectDecl( cLoc,
+				    currClause->targetName,
+				    new ReferenceType(
+				        new TypeofType( new UntypedExpr( cLoc,
+				            new NameExpr( cLoc, "__CFA_select_get_type" ),
+				            { ast::deepCopy( stmt->clauses.at(i)->target ) }
+				        ))
+				    ),
+				    new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->target ) )
+				)
+			)
+		);
+
+		// bool __when_cond_0 = when_cond; // only generated if when_cond defined
+		if ( stmt->clauses.at(i)->when_cond )
+			body->push_back(
+				new DeclStmt( cLoc,
+				    new ObjectDecl( cLoc,
+				        currClause->whenName,
+				        new BasicType( BasicKind::Bool ),
+				        new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->when_cond ) )
+				    )
+				)
+			);
+
+		// select_node clause1;
+		body->push_back(
+			new DeclStmt( cLoc,
+				new ObjectDecl( cLoc,
+				    currClause->nodeName,
+				    new StructInstType( selectNodeDecl )
+				)
+			)
+		);
+	}
+
+	if ( stmt->else_stmt && stmt->else_cond ) {
+		body->push_back(
+			new DeclStmt( stmt->else_cond->location,
+				new ObjectDecl( stmt->else_cond->location,
+				    elseWhenName,
+				    new BasicType( BasicKind::Bool ),
+				    new SingleInit( stmt->else_cond->location, ast::deepCopy( stmt->else_cond ) )
+				)
+			)
+		);
+	}
 }
 
@@ -929,27 +929,27 @@
 */
 Stmt * GenerateWaitUntilCore::buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data ) {
-    const CodeLocation & loc = stmt->location;
-
-    IfStmt * outerIf = nullptr;
+	const CodeLocation & loc = stmt->location;
+
+	IfStmt * outerIf = nullptr;
 	IfStmt * lastIf = nullptr;
 
 	//adds an if/elif clause for each select clause address to run the corresponding clause stmt
 	for ( long unsigned int i = 0; i < data.size(); i++ ) {
-        const CodeLocation & cLoc = stmt->clauses.at(i)->location;
+		const CodeLocation & cLoc = stmt->clauses.at(i)->location;
 
 		IfStmt * currIf = new IfStmt( cLoc,
-			new UntypedExpr( cLoc, 
-                new NameExpr( cLoc, "?==?" ), 
-                {
-                    new NameExpr( cLoc, statusName ),
-                    new CastExpr( cLoc, 
-                        new AddressExpr( cLoc, new NameExpr( cLoc, data.at(i)->nodeName ) ),
-                        new BasicType( BasicKind::LongUnsignedInt ), GeneratedFlag::ExplicitCast 
-                    )
-                }
-            ),
-            genStmtBlock( stmt->clauses.at(i), data.at(i) )
-		);
-		
+			new UntypedExpr( cLoc,
+				new NameExpr( cLoc, "?==?" ),
+				{
+				    new NameExpr( cLoc, statusName ),
+				    new CastExpr( cLoc,
+				        new AddressExpr( cLoc, new NameExpr( cLoc, data.at(i)->nodeName ) ),
+				        new BasicType( BasicKind::LongUnsignedInt ), GeneratedFlag::ExplicitCast
+				    )
+				}
+			),
+			genStmtBlock( stmt->clauses.at(i), data.at(i) )
+		);
+
 		if ( i == 0 ) {
 			outerIf = currIf;
@@ -962,92 +962,92 @@
 	}
 
-    return new CompoundStmt( loc,
-        {
-            new ExprStmt( loc, new UntypedExpr( loc, new NameExpr( loc, "park" ) ) ),
-            outerIf
-        }
-    );
+	return new CompoundStmt( loc,
+		{
+			new ExprStmt( loc, new UntypedExpr( loc, new NameExpr( loc, "park" ) ) ),
+			outerIf
+		}
+	);
 }
 
 Stmt * GenerateWaitUntilCore::recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName ) {
-    if ( idx == data.size() ) {   // base case, gen last else
-        const CodeLocation & cLoc = stmt->else_stmt->location;
-        if ( !stmt->else_stmt ) // normal non-else gen
-            return buildOrCaseSwitch( stmt, data.at(0)->statusName, data );
-
-        Expr * raceFnCall = new UntypedExpr( stmt->location,
-            new NameExpr( stmt->location, "__select_node_else_race" ),
-            { new NameExpr( stmt->location, data.at(0)->nodeName ) }
-        );
-
-        if ( stmt->else_stmt && stmt->else_cond ) { // return else conditional on both when and race
-            return new IfStmt( cLoc,
-                new LogicalExpr( cLoc,
-                    new CastExpr( cLoc,
-                        new NameExpr( cLoc, elseWhenName ),
-                        new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-                    ),
-                    new CastExpr( cLoc,
-                        raceFnCall,
-                        new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-                    ),
-                    LogicalFlag::AndExpr
-                ),
-                ast::deepCopy( stmt->else_stmt ),
-                buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
-            );
-        }
-
-        // return else conditional on race
-        return new IfStmt( stmt->else_stmt->location,
-            raceFnCall,
-            ast::deepCopy( stmt->else_stmt ),
-            buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
-        );
-    }
-    const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
-
-    Expr * baseCond = genSelectTraitCall( stmt->clauses.at(idx), data.at(idx), "register_select" );
-    Expr * ifCond;
-
-    // If we have a when_cond make the register call conditional on it
-    if ( stmt->clauses.at(idx)->when_cond ) {
-        ifCond = new LogicalExpr( cLoc,
-            new CastExpr( cLoc,
-                new NameExpr( cLoc, data.at(idx)->whenName ), 
-                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-            ),
-            new CastExpr( cLoc,
-                baseCond,
-                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-            ),
-            LogicalFlag::AndExpr
-        );
-    } else ifCond = baseCond;
-
-    return new CompoundStmt( cLoc,
-        {   // gens: setup_clause( clause1, &status, 0p );
-            new ExprStmt( cLoc,
-                new UntypedExpr ( cLoc,
-                    new NameExpr( cLoc, "setup_clause" ),
-                    {
-                        new NameExpr( cLoc, data.at(idx)->nodeName ),
-                        new AddressExpr( cLoc, new NameExpr( cLoc, data.at(idx)->statusName ) ),
-                        ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::SignedInt ) ) )
-                    }
-                )
-            ),
-            // gens: if (__when_cond && register_select()) { clause body } else { ... recursiveOrIfGen ... }
-            new IfStmt( cLoc,
-                ifCond,
-                genStmtBlock( stmt->clauses.at(idx), data.at(idx) ),
-                recursiveOrIfGen( stmt, data, idx + 1, elseWhenName )
-            )
-        }
-    );
+	if ( idx == data.size() ) {   // base case, gen last else
+		const CodeLocation & cLoc = stmt->else_stmt->location;
+		if ( !stmt->else_stmt ) // normal non-else gen
+			return buildOrCaseSwitch( stmt, data.at(0)->statusName, data );
+
+		Expr * raceFnCall = new UntypedExpr( stmt->location,
+			new NameExpr( stmt->location, "__select_node_else_race" ),
+			{ new NameExpr( stmt->location, data.at(0)->nodeName ) }
+		);
+
+		if ( stmt->else_stmt && stmt->else_cond ) { // return else conditional on both when and race
+			return new IfStmt( cLoc,
+				new LogicalExpr( cLoc,
+				    new CastExpr( cLoc,
+				        new NameExpr( cLoc, elseWhenName ),
+				        new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+				    ),
+				    new CastExpr( cLoc,
+				        raceFnCall,
+				        new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+				    ),
+				    LogicalFlag::AndExpr
+				),
+				ast::deepCopy( stmt->else_stmt ),
+				buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
+			);
+		}
+
+		// return else conditional on race
+		return new IfStmt( stmt->else_stmt->location,
+			raceFnCall,
+			ast::deepCopy( stmt->else_stmt ),
+			buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
+		);
+	}
+	const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
+
+	Expr * baseCond = genSelectTraitCall( stmt->clauses.at(idx), data.at(idx), "register_select" );
+	Expr * ifCond;
+
+	// If we have a when_cond make the register call conditional on it
+	if ( stmt->clauses.at(idx)->when_cond ) {
+		ifCond = new LogicalExpr( cLoc,
+			new CastExpr( cLoc,
+				new NameExpr( cLoc, data.at(idx)->whenName ),
+				new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+			),
+			new CastExpr( cLoc,
+				baseCond,
+				new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+			),
+			LogicalFlag::AndExpr
+		);
+	} else ifCond = baseCond;
+
+	return new CompoundStmt( cLoc,
+		{   // gens: setup_clause( clause1, &status, 0p );
+			new ExprStmt( cLoc,
+				new UntypedExpr ( cLoc,
+				    new NameExpr( cLoc, "setup_clause" ),
+				    {
+				        new NameExpr( cLoc, data.at(idx)->nodeName ),
+				        new AddressExpr( cLoc, new NameExpr( cLoc, data.at(idx)->statusName ) ),
+				        ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::SignedInt ) ) )
+				    }
+				)
+			),
+			// gens: if (__when_cond && register_select()) { clause body } else { ... recursiveOrIfGen ... }
+			new IfStmt( cLoc,
+				ifCond,
+				genStmtBlock( stmt->clauses.at(idx), data.at(idx) ),
+				recursiveOrIfGen( stmt, data, idx + 1, elseWhenName )
+			)
+		}
+	);
 }
 
 // This gens the special case of an all OR waituntil:
-/* 
+/*
 int status = 0;
 
@@ -1058,340 +1058,340 @@
 
 try {
-    setup_clause( clause1, &status, 0p );
-    if ( __when_cond_0 && register_select( 1 ) ) {
-        ... clause 1 body ...
-    } else {
-        ... recursively gen for each of n clauses ...
-        setup_clause( clausen, &status, 0p );
-        if ( __when_cond_n-1 && register_select( n ) ) {
-            ... clause n body ...
-        } else {
-            if ( else_when ) ... else clause body ...
-            else {
-                park();
-
-                // after winning the race and before unpark() clause_status is set to be the winning clause index + 1 
-                if ( clause_status == &clause1) ... clause 1 body ...
-                ...
-                elif ( clause_status == &clausen ) ... clause n body ...
-            }
-        }
-    }
-}
-finally { 
-    if ( __when_cond_1 && clause1.status != 0p) unregister_select( 1 ); // if registered unregister
-    ...
-    if ( __when_cond_n && clausen.status != 0p) unregister_select( n );
+	setup_clause( clause1, &status, 0p );
+	if ( __when_cond_0 && register_select( 1 ) ) {
+		... clause 1 body ...
+	} else {
+		... recursively gen for each of n clauses ...
+		setup_clause( clausen, &status, 0p );
+		if ( __when_cond_n-1 && register_select( n ) ) {
+			... clause n body ...
+		} else {
+			if ( else_when ) ... else clause body ...
+			else {
+				park();
+
+				// after winning the race and before unpark() clause_status is set to be the winning clause index + 1
+				if ( clause_status == &clause1) ... clause 1 body ...
+				...
+				elif ( clause_status == &clausen ) ... clause n body ...
+			}
+		}
+	}
+}
+finally {
+	if ( __when_cond_1 && clause1.status != 0p) unregister_select( 1 ); // if registered unregister
+	...
+	if ( __when_cond_n && clausen.status != 0p) unregister_select( n );
 }
 */
 Stmt * GenerateWaitUntilCore::genAllOr( const WaitUntilStmt * stmt ) {
-    const CodeLocation & loc = stmt->location;
-    string statusName = namer_status.newName();
-    string elseWhenName = namer_when.newName();
-    int numClauses = stmt->clauses.size();
-    CompoundStmt * body = new CompoundStmt( stmt->location );
-
-    // Generates: unsigned long int status = 0;
-    body->push_back( new DeclStmt( loc,
-        new ObjectDecl( loc,
-            statusName,
-            new BasicType( BasicKind::LongUnsignedInt ),
-            new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
-        )
-    ));
-
-    vector<ClauseData *> clauseData;
-    genClauseInits( stmt, clauseData, body, statusName, elseWhenName );
-
-    vector<int> whenIndices; // track which clauses have whens
-
-    CompoundStmt * unregisters = new CompoundStmt( loc );
-    Expr * ifCond;
-    for ( int i = 0; i < numClauses; i++ ) {
-        const CodeLocation & cLoc = stmt->clauses.at(i)->location;
-        // Gens: node.status != 0p
-        UntypedExpr * statusPtrCheck = new UntypedExpr( cLoc, 
-            new NameExpr( cLoc, "?!=?" ), 
-            {
-                ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::LongUnsignedInt ) ) ),
-                new UntypedExpr( cLoc, 
-                    new NameExpr( cLoc, "__get_clause_status" ), 
-                    { new NameExpr( cLoc, clauseData.at(i)->nodeName ) } 
-                ) 
-            }
-        );
-
-        // If we have a when_cond make the unregister call conditional on it
-        if ( stmt->clauses.at(i)->when_cond ) {
-            whenIndices.push_back(i);
-            ifCond = new LogicalExpr( cLoc,
-                new CastExpr( cLoc,
-                    new NameExpr( cLoc, clauseData.at(i)->whenName ), 
-                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-                ),
-                new CastExpr( cLoc,
-                    statusPtrCheck,
-                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-                ),
-                LogicalFlag::AndExpr
-            );
-        } else ifCond = statusPtrCheck;
-        
-        unregisters->push_back(
-            new IfStmt( cLoc,
-                ifCond,
-                new ExprStmt( cLoc, genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ) ) 
-            )
-        );
-    }
-
-    if ( whenIndices.empty() || whenIndices.size() != stmt->clauses.size() ) {
-        body->push_back(
-                new ast::TryStmt( loc,
-                new CompoundStmt( loc, { recursiveOrIfGen( stmt, clauseData, 0, elseWhenName ) } ),
-                {},
-                new ast::FinallyClause( loc, unregisters )
-            )
-        );
-    } else { // If all clauses have whens, we need to skip the waituntil if they are all false
-        Expr * outerIfCond = new NameExpr( loc, clauseData.at( whenIndices.at(0) )->whenName );
-        Expr * lastExpr = outerIfCond;
-
-        for ( vector<int>::size_type i = 1; i < whenIndices.size(); i++ ) {
-            outerIfCond = new LogicalExpr( loc,
-                new CastExpr( loc,
-                    new NameExpr( loc, clauseData.at( whenIndices.at(i) )->whenName ), 
-                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-                ),
-                new CastExpr( loc,
-                    lastExpr,
-                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-                ),
-                LogicalFlag::OrExpr
-            );
-            lastExpr = outerIfCond;
-        }
-
-        body->push_back(
-                new ast::TryStmt( loc,
-                new CompoundStmt( loc, 
-                    {
-                        new IfStmt( loc,
-                            outerIfCond,
-                            recursiveOrIfGen( stmt, clauseData, 0, elseWhenName )
-                        )
-                    }
-                ),
-                {},
-                new ast::FinallyClause( loc, unregisters )
-            )
-        );
-    }
-
-    for ( ClauseData * datum : clauseData )
-        delete datum;
-
-    return body;
+	const CodeLocation & loc = stmt->location;
+	string statusName = namer_status.newName();
+	string elseWhenName = namer_when.newName();
+	int numClauses = stmt->clauses.size();
+	CompoundStmt * body = new CompoundStmt( stmt->location );
+
+	// Generates: unsigned long int status = 0;
+	body->push_back( new DeclStmt( loc,
+		new ObjectDecl( loc,
+			statusName,
+			new BasicType( BasicKind::LongUnsignedInt ),
+			new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
+		)
+	));
+
+	vector<ClauseData *> clauseData;
+	genClauseInits( stmt, clauseData, body, statusName, elseWhenName );
+
+	vector<int> whenIndices; // track which clauses have whens
+
+	CompoundStmt * unregisters = new CompoundStmt( loc );
+	Expr * ifCond;
+	for ( int i = 0; i < numClauses; i++ ) {
+		const CodeLocation & cLoc = stmt->clauses.at(i)->location;
+		// Gens: node.status != 0p
+		UntypedExpr * statusPtrCheck = new UntypedExpr( cLoc,
+			new NameExpr( cLoc, "?!=?" ),
+			{
+				ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::LongUnsignedInt ) ) ),
+				new UntypedExpr( cLoc,
+				    new NameExpr( cLoc, "__get_clause_status" ),
+				    { new NameExpr( cLoc, clauseData.at(i)->nodeName ) }
+				)
+			}
+		);
+
+		// If we have a when_cond make the unregister call conditional on it
+		if ( stmt->clauses.at(i)->when_cond ) {
+			whenIndices.push_back(i);
+			ifCond = new LogicalExpr( cLoc,
+				new CastExpr( cLoc,
+				    new NameExpr( cLoc, clauseData.at(i)->whenName ),
+				    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+				),
+				new CastExpr( cLoc,
+				    statusPtrCheck,
+				    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+				),
+				LogicalFlag::AndExpr
+			);
+		} else ifCond = statusPtrCheck;
+
+		unregisters->push_back(
+			new IfStmt( cLoc,
+				ifCond,
+				new ExprStmt( cLoc, genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ) )
+			)
+		);
+	}
+
+	if ( whenIndices.empty() || whenIndices.size() != stmt->clauses.size() ) {
+		body->push_back(
+				new ast::TryStmt( loc,
+				new CompoundStmt( loc, { recursiveOrIfGen( stmt, clauseData, 0, elseWhenName ) } ),
+				{},
+				new ast::FinallyClause( loc, unregisters )
+			)
+		);
+	} else { // If all clauses have whens, we need to skip the waituntil if they are all false
+		Expr * outerIfCond = new NameExpr( loc, clauseData.at( whenIndices.at(0) )->whenName );
+		Expr * lastExpr = outerIfCond;
+
+		for ( vector<int>::size_type i = 1; i < whenIndices.size(); i++ ) {
+			outerIfCond = new LogicalExpr( loc,
+				new CastExpr( loc,
+				    new NameExpr( loc, clauseData.at( whenIndices.at(i) )->whenName ),
+				    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+				),
+				new CastExpr( loc,
+				    lastExpr,
+				    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+				),
+				LogicalFlag::OrExpr
+			);
+			lastExpr = outerIfCond;
+		}
+
+		body->push_back(
+				new ast::TryStmt( loc,
+				new CompoundStmt( loc,
+				    {
+				        new IfStmt( loc,
+				            outerIfCond,
+				            recursiveOrIfGen( stmt, clauseData, 0, elseWhenName )
+				        )
+				    }
+				),
+				{},
+				new ast::FinallyClause( loc, unregisters )
+			)
+		);
+	}
+
+	for ( ClauseData * datum : clauseData )
+		delete datum;
+
+	return body;
 }
 
 Stmt * GenerateWaitUntilCore::postvisit( const WaitUntilStmt * stmt ) {
-    if ( !selectNodeDecl )
-        SemanticError( stmt, "waituntil statement requires #include <waituntil.hfa>" );
-
-    // Prep clause tree to figure out how to set initial statuses
-    // setTreeSizes( stmt->predicateTree );
-    if ( paintWhenTree( stmt->predicateTree ) ) // if this returns true we can special case since tree is all OR's
-        return genAllOr( stmt );
-
-    CompoundStmt * tryBody = new CompoundStmt( stmt->location );
-    CompoundStmt * body = new CompoundStmt( stmt->location );
-    string statusArrName = namer_status.newName();
-    string pCountName = namer_park.newName();
-    string satName = namer_sat.newName();
-    string runName = namer_run.newName();
-    string elseWhenName = namer_when.newName();
-    int numClauses = stmt->clauses.size();
-    addPredicates( stmt, satName, runName );
-
-    const CodeLocation & loc = stmt->location;
-
-    // Generates: int park_counter = 0;
-    body->push_back( new DeclStmt( loc,
-        new ObjectDecl( loc,
-            pCountName,
-            new BasicType( BasicKind::SignedInt ),
-            new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
-        )
-    ));
-
-    // Generates: int clause_statuses[3] = { 0 };
-    body->push_back( new DeclStmt( loc,
-        new ObjectDecl( loc,
-            statusArrName,
-            new ArrayType( new BasicType( BasicKind::LongUnsignedInt ), ConstantExpr::from_int( loc, numClauses ), LengthFlag::FixedLen, DimensionFlag::DynamicDim ),
-            new ListInit( loc,
-                {
-                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
-                }
-            )
-        )
-    ));
-
-    vector<ClauseData *> clauseData;
-    genClauseInits( stmt, clauseData, body, statusArrName, elseWhenName );
-
-    vector<pair<int, WaitUntilStmt::ClauseNode *>> ambiguousClauses;       // list of ambiguous clauses
-    vector<int> andWhenClauses;    // list of clauses that have an AND op as a direct parent and when_cond defined
-
-    collectWhens( stmt->predicateTree, ambiguousClauses, andWhenClauses );
-
-    // This is only needed for clauses that have AND as a parent and a when_cond defined
-    // generates: if ( ! when_cond_0 ) clause_statuses_0 = __SELECT_RUN;
-    for ( int idx : andWhenClauses ) {
-        const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
-        body->push_back( 
-            new IfStmt( cLoc,
-                new UntypedExpr ( cLoc,
-                    new NameExpr( cLoc, "!?" ),
-                    { new NameExpr( cLoc, clauseData.at(idx)->whenName ) }
-                ),  // IfStmt cond
-                new ExprStmt( cLoc,
-                    new UntypedExpr ( cLoc,
-                        new NameExpr( cLoc, "?=?" ),
-                        {
-                            new UntypedExpr ( cLoc, 
-                                new NameExpr( cLoc, "?[?]" ),
-                                {
-                                    new NameExpr( cLoc, statusArrName ),
-                                    ConstantExpr::from_int( cLoc, idx )
-                                }
-                            ),
-                            new NameExpr( cLoc, "__SELECT_RUN" )
-                        }
-                    )
-                )  // IfStmt then
-            )
-        );
-    }
-
-    // Only need to generate conditional initial state setting for ambiguous when clauses
-    if ( !ambiguousClauses.empty() ) {
-        body->push_back( genWhenStateConditions( stmt, clauseData, ambiguousClauses, 0 ) );
-    }
-
-    // generates the following for each clause:
-    // setup_clause( clause1, &clause_statuses[0], &park_counter );
-    // register_select(A, clause1);
-    for ( int i = 0; i < numClauses; i++ ) {
-        setUpClause( stmt->clauses.at(i), clauseData.at(i), pCountName, tryBody );
-    }
-
-    // generate satisfy logic based on if there is an else clause and if it is conditional
-    if ( stmt->else_stmt && stmt->else_cond ) { // gen both else/non else branches
-        tryBody->push_back(
-            new IfStmt( stmt->else_cond->location,
-                new NameExpr( stmt->else_cond->location, elseWhenName ),
-                genElseClauseBranch( stmt, runName, statusArrName, clauseData ),
-                genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData )
-            )
-        );
-    } else if ( !stmt->else_stmt ) { // normal gen
-        tryBody->push_back( genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) );
-    } else { // generate just else
-        tryBody->push_back( genElseClauseBranch( stmt, runName, statusArrName, clauseData ) );
-    }
-
-    // Collection of unregister calls on resources to be put in finally clause
-    // for each clause: 
-    // if ( !__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
-    // OR if when( ... ) defined on resource
-    // if ( when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
-    CompoundStmt * unregisters = new CompoundStmt( loc );
-
-    Expr * statusExpr; // !__CFA_has_clause_run( clause_statuses[i] )
-    for ( int i = 0; i < numClauses; i++ ) {
-        const CodeLocation & cLoc = stmt->clauses.at(i)->location;
-
-        // Generates: !__CFA_has_clause_run( clause_statuses[i] )
-        statusExpr = new UntypedExpr ( cLoc,
-            new NameExpr( cLoc, "!?" ),
-            {
-                new UntypedExpr ( cLoc, 
-                    new NameExpr( cLoc, "__CFA_has_clause_run" ),
-                    {
-                        genArrAccessExpr( cLoc, i, statusArrName )
-                    }
-                )
-            }
-        );
-        
-        // Generates:
-        // (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
-        statusExpr = new LogicalExpr( cLoc,
-            new CastExpr( cLoc,
-                statusExpr, 
-                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-            ),
-            new CastExpr( cLoc,
-                genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
-                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-            ),
-            LogicalFlag::AndExpr
-        );
-        
-        // if when cond defined generates:
-        // when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
-        if ( stmt->clauses.at(i)->when_cond )
-            statusExpr = new LogicalExpr( cLoc,
-                new CastExpr( cLoc,
-                    new NameExpr( cLoc, clauseData.at(i)->whenName ), 
-                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-                ),
-                new CastExpr( cLoc,
-                    statusExpr,
-                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 
-                ),
-                LogicalFlag::AndExpr
-            );
-
-        // generates:
-        // if ( statusExpr ) { ... clausei stmt ... }
-        unregisters->push_back( 
-            new IfStmt( cLoc,
-                statusExpr,
-                new CompoundStmt( cLoc,
-                    {
-                        new IfStmt( cLoc,
-                            genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ),
-                            ast::deepCopy( stmt->clauses.at(i)->stmt )
-                        )
-                    }
-                )
-            )
-        );
-
-        // // generates:
-        // // if ( statusExpr ) { ... clausei stmt ... }
-        // unregisters->push_back( 
-        //     new IfStmt( cLoc,
-        //         statusExpr,
-        //         genStmtBlock( stmt->clauses.at(i), clauseData.at(i) )
-        //     )
-        // );
-    }
-
-    body->push_back( 
-        new ast::TryStmt(
-            loc,
-            tryBody,
-            {},
-            new ast::FinallyClause( loc, unregisters )
-        )
-    );
-
-    for ( ClauseData * datum : clauseData )
-        delete datum;
-
-    return body;
+	if ( !selectNodeDecl )
+		SemanticError( stmt, "waituntil statement requires #include <waituntil.hfa>" );
+
+	// Prep clause tree to figure out how to set initial statuses
+	// setTreeSizes( stmt->predicateTree );
+	if ( paintWhenTree( stmt->predicateTree ) ) // if this returns true we can special case since tree is all OR's
+		return genAllOr( stmt );
+
+	CompoundStmt * tryBody = new CompoundStmt( stmt->location );
+	CompoundStmt * body = new CompoundStmt( stmt->location );
+	string statusArrName = namer_status.newName();
+	string pCountName = namer_park.newName();
+	string satName = namer_sat.newName();
+	string runName = namer_run.newName();
+	string elseWhenName = namer_when.newName();
+	int numClauses = stmt->clauses.size();
+	addPredicates( stmt, satName, runName );
+
+	const CodeLocation & loc = stmt->location;
+
+	// Generates: int park_counter = 0;
+	body->push_back( new DeclStmt( loc,
+		new ObjectDecl( loc,
+			pCountName,
+			new BasicType( BasicKind::SignedInt ),
+			new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
+		)
+	));
+
+	// Generates: int clause_statuses[3] = { 0 };
+	body->push_back( new DeclStmt( loc,
+		new ObjectDecl( loc,
+			statusArrName,
+			new ArrayType( new BasicType( BasicKind::LongUnsignedInt ), ConstantExpr::from_int( loc, numClauses ), LengthFlag::FixedLen, DimensionFlag::DynamicDim ),
+			new ListInit( loc,
+				{
+				    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
+				}
+			)
+		)
+	));
+
+	vector<ClauseData *> clauseData;
+	genClauseInits( stmt, clauseData, body, statusArrName, elseWhenName );
+
+	vector<pair<int, WaitUntilStmt::ClauseNode *>> ambiguousClauses;       // list of ambiguous clauses
+	vector<int> andWhenClauses;    // list of clauses that have an AND op as a direct parent and when_cond defined
+
+	collectWhens( stmt->predicateTree, ambiguousClauses, andWhenClauses );
+
+	// This is only needed for clauses that have AND as a parent and a when_cond defined
+	// generates: if ( ! when_cond_0 ) clause_statuses_0 = __SELECT_RUN;
+	for ( int idx : andWhenClauses ) {
+		const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
+		body->push_back(
+			new IfStmt( cLoc,
+				new UntypedExpr ( cLoc,
+				    new NameExpr( cLoc, "!?" ),
+				    { new NameExpr( cLoc, clauseData.at(idx)->whenName ) }
+				),  // IfStmt cond
+				new ExprStmt( cLoc,
+				    new UntypedExpr ( cLoc,
+				        new NameExpr( cLoc, "?=?" ),
+				        {
+				            new UntypedExpr ( cLoc,
+				                new NameExpr( cLoc, "?[?]" ),
+				                {
+				                    new NameExpr( cLoc, statusArrName ),
+				                    ConstantExpr::from_int( cLoc, idx )
+				                }
+				            ),
+				            new NameExpr( cLoc, "__SELECT_RUN" )
+				        }
+				    )
+				)  // IfStmt then
+			)
+		);
+	}
+
+	// Only need to generate conditional initial state setting for ambiguous when clauses
+	if ( !ambiguousClauses.empty() ) {
+		body->push_back( genWhenStateConditions( stmt, clauseData, ambiguousClauses, 0 ) );
+	}
+
+	// generates the following for each clause:
+	// setup_clause( clause1, &clause_statuses[0], &park_counter );
+	// register_select(A, clause1);
+	for ( int i = 0; i < numClauses; i++ ) {
+		setUpClause( stmt->clauses.at(i), clauseData.at(i), pCountName, tryBody );
+	}
+
+	// generate satisfy logic based on if there is an else clause and if it is conditional
+	if ( stmt->else_stmt && stmt->else_cond ) { // gen both else/non else branches
+		tryBody->push_back(
+			new IfStmt( stmt->else_cond->location,
+				new NameExpr( stmt->else_cond->location, elseWhenName ),
+				genElseClauseBranch( stmt, runName, statusArrName, clauseData ),
+				genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData )
+			)
+		);
+	} else if ( !stmt->else_stmt ) { // normal gen
+		tryBody->push_back( genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) );
+	} else { // generate just else
+		tryBody->push_back( genElseClauseBranch( stmt, runName, statusArrName, clauseData ) );
+	}
+
+	// Collection of unregister calls on resources to be put in finally clause
+	// for each clause:
+	// if ( !__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
+	// OR if when( ... ) defined on resource
+	// if ( when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
+	CompoundStmt * unregisters = new CompoundStmt( loc );
+
+	Expr * statusExpr; // !__CFA_has_clause_run( clause_statuses[i] )
+	for ( int i = 0; i < numClauses; i++ ) {
+		const CodeLocation & cLoc = stmt->clauses.at(i)->location;
+
+		// Generates: !__CFA_has_clause_run( clause_statuses[i] )
+		statusExpr = new UntypedExpr ( cLoc,
+			new NameExpr( cLoc, "!?" ),
+			{
+				new UntypedExpr ( cLoc,
+				    new NameExpr( cLoc, "__CFA_has_clause_run" ),
+				    {
+				        genArrAccessExpr( cLoc, i, statusArrName )
+				    }
+				)
+			}
+		);
+
+		// Generates:
+		// (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
+		statusExpr = new LogicalExpr( cLoc,
+			new CastExpr( cLoc,
+				statusExpr,
+				new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+			),
+			new CastExpr( cLoc,
+				genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
+				new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+			),
+			LogicalFlag::AndExpr
+		);
+
+		// if when cond defined generates:
+		// when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
+		if ( stmt->clauses.at(i)->when_cond )
+			statusExpr = new LogicalExpr( cLoc,
+				new CastExpr( cLoc,
+				    new NameExpr( cLoc, clauseData.at(i)->whenName ),
+				    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+				),
+				new CastExpr( cLoc,
+				    statusExpr,
+				    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
+				),
+				LogicalFlag::AndExpr
+			);
+
+		// generates:
+		// if ( statusExpr ) { ... clausei stmt ... }
+		unregisters->push_back(
+			new IfStmt( cLoc,
+				statusExpr,
+				new CompoundStmt( cLoc,
+				    {
+				        new IfStmt( cLoc,
+				            genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ),
+				            ast::deepCopy( stmt->clauses.at(i)->stmt )
+				        )
+				    }
+				)
+			)
+		);
+
+		// // generates:
+		// // if ( statusExpr ) { ... clausei stmt ... }
+		// unregisters->push_back(
+		//     new IfStmt( cLoc,
+		//         statusExpr,
+		//         genStmtBlock( stmt->clauses.at(i), clauseData.at(i) )
+		//     )
+		// );
+	}
+
+	body->push_back(
+		new ast::TryStmt(
+			loc,
+			tryBody,
+			{},
+			new ast::FinallyClause( loc, unregisters )
+		)
+	);
+
+	for ( ClauseData * datum : clauseData )
+		delete datum;
+
+	return body;
 }
 
@@ -1399,25 +1399,25 @@
 // Predicates are added after "struct select_node { ... };"
 class AddPredicateDecls final : public WithDeclsToAdd<> {
-    vector<FunctionDecl *> & satFns;
-    const StructDecl * selectNodeDecl = nullptr;
+	vector<FunctionDecl *> & satFns;
+	const StructDecl * selectNodeDecl = nullptr;
 
   public:
-    void previsit( const StructDecl * decl ) {
-        if ( !decl->body ) {
-            return;
-        } else if ( "select_node" == decl->name ) {
-            assert( !selectNodeDecl );
-            selectNodeDecl = decl;
-            for ( FunctionDecl * fn : satFns )
-                declsToAddAfter.push_back(fn);            
-        }
-    }
-    AddPredicateDecls( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
+	void previsit( const StructDecl * decl ) {
+		if ( !decl->body ) {
+			return;
+		} else if ( "select_node" == decl->name ) {
+			assert( !selectNodeDecl );
+			selectNodeDecl = decl;
+			for ( FunctionDecl * fn : satFns )
+				declsToAddAfter.push_back(fn);
+		}
+	}
+	AddPredicateDecls( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
 };
 
 void generateWaitUntil( TranslationUnit & translationUnit ) {
-    vector<FunctionDecl *> satFns;
+	vector<FunctionDecl *> satFns;
 	Pass<GenerateWaitUntilCore>::run( translationUnit, satFns );
-    Pass<AddPredicateDecls>::run( translationUnit, satFns );
+	Pass<AddPredicateDecls>::run( translationUnit, satFns );
 }
 
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Parser/parser.yy	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Mar 16 18:19:23 2024
-// Update Count     : 6617
+// Last Modified On : Tue Apr 23 15:39:29 2024
+// Update Count     : 6620
 //
 
@@ -493,5 +493,5 @@
 %type<decl> exception_declaration
 
-%type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract
+%type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declaring_list field_declarator field_abstract_list_opt field_abstract
 %type<expr> field field_name_list field_name fraction_constants_opt
 
@@ -2682,6 +2682,10 @@
 	// empty
 		{ $$ = nullptr; }
-	| field_declarator
-	| field_declaring_list_opt ',' attribute_list_opt field_declarator
+	| field_declaring_list
+	;
+
+field_declaring_list:
+	field_declarator
+	| field_declaring_list ',' attribute_list_opt field_declarator
 		{ $$ = $1->set_last( $4->addQualifiers( $3 ) ); }
 	;
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -1412,10 +1412,10 @@
 	}
 
-    void Finder::postvisit(const ast::VariableExpr *variableExpr) {
-        // not sufficient to just pass `variableExpr` here, type might have changed
-
-        auto cand = new Candidate(variableExpr, tenv);
-        candidates.emplace_back(cand);
-    }
+	void Finder::postvisit(const ast::VariableExpr *variableExpr) {
+		// not sufficient to just pass `variableExpr` here, type might have changed
+
+		auto cand = new Candidate(variableExpr, tenv);
+		candidates.emplace_back(cand);
+	}
 
 	void Finder::postvisit( const ast::ConstantExpr * constantExpr ) {
@@ -2133,6 +2133,6 @@
 
 // get the valueE(...) ApplicationExpr that returns the enum value
-const ast::Expr * getValueEnumCall( 
-	const ast::Expr * expr, 
+const ast::Expr * getValueEnumCall(
+	const ast::Expr * expr,
 	const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env ) {
 		auto callExpr = new ast::UntypedExpr(
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/ResolvExpr/CommonType.cc	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -36,4 +36,6 @@
 namespace ResolvExpr {
 
+namespace {
+
 	// GENERATED START, DO NOT EDIT
 	// GENERATED BY BasicTypes-gen.cc
@@ -397,15 +399,15 @@
 			}
 		} else if ( auto type2AsAttr = dynamic_cast< const ast::EnumAttrType * >( type2 ) ) {
-            if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
-			    ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::SignedInt ];
-			    if (
-				    ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
-					    || widen.first )
-				    && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
-					    || widen.second )
-			    ) {
-				    result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
-			    }
-            }
+			if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
+				ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::SignedInt ];
+				if (
+					( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
+						|| widen.first )
+					&& ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
+						|| widen.second )
+				) {
+					result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
+				}
+			}
 		}
 	}
@@ -519,5 +521,5 @@
 								// xxx - assume LHS is always the target type
 
-								if ( ! ((widen.second && ref2->qualifiers.is_mutex) 
+								if ( ! ((widen.second && ref2->qualifiers.is_mutex)
 								|| (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return;
 
@@ -710,35 +712,35 @@
 // size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType");
 
-namespace {
-	ast::ptr< ast::Type > handleReference(
-		const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen,
-		ast::TypeEnvironment & env,
-		const ast::OpenVarSet & open
-	) {
-		ast::ptr<ast::Type> common;
-		ast::AssertionSet have, need;
-		ast::OpenVarSet newOpen{ open };
-
-		// need unify to bind type variables
-		if ( unify( t1, t2, env, have, need, newOpen, common ) ) {
-			ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers;
+ast::ptr< ast::Type > handleReference(
+	const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen,
+	ast::TypeEnvironment & env,
+	const ast::OpenVarSet & open
+) {
+	ast::ptr<ast::Type> common;
+	ast::AssertionSet have, need;
+	ast::OpenVarSet newOpen( open );
+
+	// need unify to bind type variables
+	if ( unify( t1, t2, env, have, need, newOpen, common ) ) {
+		ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers;
+		PRINT(
+			std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
+		)
+		if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) {
 			PRINT(
-				std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
+				std::cerr << "widen okay" << std::endl;
 			)
-			if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) {
-				PRINT(
-					std::cerr << "widen okay" << std::endl;
-				)
-				add_qualifiers( common, q1 | q2 );
-				return common;
-			}
-		}
-
-		PRINT(
-			std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
-		)
-		return { nullptr };
-	}
+			add_qualifiers( common, q1 | q2 );
+			return common;
+		}
+	}
+
+	PRINT(
+		std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
+	)
+	return { nullptr };
 }
+
+} // namespace
 
 ast::ptr< ast::Type > commonType(
@@ -781,9 +783,6 @@
 	}
 	// otherwise both are reference types of the same depth and this is handled by the visitor
-	ast::Pass<CommonType> visitor{ type2, widen, env, open, need, have };
-	type1->accept( visitor );
-	// ast::ptr< ast::Type > result = visitor.core.result;
-
-	return visitor.core.result;
+	return ast::Pass<CommonType>::read( type1.get(),
+		type2, widen, env, open, need, have );
 }
 
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/ResolvExpr/ConversionCost.cc	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -31,4 +31,6 @@
 #define PRINT(x)
 #endif
+
+namespace {
 
 	// GENERATED START, DO NOT EDIT
@@ -152,5 +154,4 @@
 	);
 
-namespace {
 	int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
 			const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
@@ -379,28 +380,28 @@
 
 void ConversionCost::postvisit( const ast::EnumAttrType * src ) {
-    auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
+	auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
 	assert( src->attr != ast::EnumAttribute::Label );
-    if ( src->attr == ast::EnumAttribute::Value ) {
-        if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
-            cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
-        } else {
-            auto baseType = src->instance->base->base;
-            cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
+	if ( src->attr == ast::EnumAttribute::Value ) {
+		if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
+			cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
+		} else {
+			auto baseType = src->instance->base->base;
+			cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
 			if ( cost < Cost::infinity ) {
 				cost.incUnsafe();
 			}
-        }
-    } else { // ast::EnumAttribute::Posn
-        if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
-		    cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
-		    if ( cost < Cost::unsafe ) cost.incSafe();
-	    } else {
-		    static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
-		    cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
-		    if ( cost < Cost::unsafe ) {
-			    cost.incSafe();
-		    }
-	    }
-    }
+		}
+	} else { // ast::EnumAttribute::Posn
+		if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
+			cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
+			if ( cost < Cost::unsafe ) cost.incSafe();
+		} else {
+			static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
+			cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
+			if ( cost < Cost::unsafe ) {
+				cost.incSafe();
+			}
+		}
+	}
 }
 
Index: src/ResolvExpr/PolyCost.cc
===================================================================
--- src/ResolvExpr/PolyCost.cc	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/ResolvExpr/PolyCost.cc	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -29,17 +29,17 @@
 	const ast::TypeEnvironment &env_;
 
-	PolyCost( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 
+	PolyCost( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
 	: symtab( symtab ), result( 0 ), env_( env ) {}
 
 	void previsit( const ast::TypeInstType * type ) {
-		if ( const ast::EqvClass * eqv = env_.lookup( *type ) ) /* && */ if ( eqv->bound ) {
+		if ( const ast::EqvClass * eqv = env_.lookup( *type ) ; eqv && eqv->bound ) {
 			if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
 				if ( symtab.lookupType( otherType->name ) ) {
 					// Bound to opaque type.
-					result += 1;
+					result = 1;
 				}
 			} else {
 				// Bound to concrete type.
-				result += 1;
+				result = 1;
 			}
 		}
@@ -52,7 +52,5 @@
 	const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
 ) {
-	ast::Pass<PolyCost> costing( symtab, env );
-	type->accept( costing );
-	return (costing.core.result > 0) ? 1 : 0;
+	return ast::Pass<PolyCost>::read( type, symtab, env );
 }
 
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/ResolvExpr/RenameVars.cc	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -30,102 +30,102 @@
 
 namespace {
-	class RenamingData {
-		int level = 0;
-		int resetCount = 0;
 
-		int next_expr_id = 1;
-		int next_usage_id = 1;
-		ScopedMap< std::string, std::string > nameMap;
-		ScopedMap< std::string, ast::TypeEnvKey > idMap;
-	public:
-		void reset() {
-			level = 0;
-			++resetCount;
+class RenamingData {
+	int level = 0;
+	int resetCount = 0;
+
+	int next_expr_id = 1;
+	int next_usage_id = 1;
+	ScopedMap< std::string, std::string > nameMap;
+	ScopedMap< std::string, ast::TypeEnvKey > idMap;
+public:
+	void reset() {
+		level = 0;
+		++resetCount;
+	}
+
+	void nextUsage() {
+		++next_usage_id;
+	}
+
+	const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
+		auto it = idMap.find( type->name );
+		if ( it == idMap.end() ) return type;
+
+		// Unconditionally mutate because map will *always* have different name.
+		ast::TypeInstType * mut = ast::shallowCopy( type );
+		// Reconcile base node since some copies might have been made.
+		mut->base = it->second.base;
+		mut->formal_usage = it->second.formal_usage;
+		mut->expr_id = it->second.expr_id;
+		return mut;
+	}
+
+	const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
+		if ( type->forall.empty() ) return type;
+		idMap.beginScope();
+
+		// Load new names from this forall clause and perform renaming.
+		auto mutType = ast::shallowCopy( type );
+		// assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
+		for ( auto & td : mutType->forall ) {
+			auto mut = ast::shallowCopy( td.get() );
+			// assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
+
+			if ( mode == GEN_EXPR_ID ) {
+				mut->expr_id = next_expr_id;
+				mut->formal_usage = -1;
+				++next_expr_id;
+			} else if ( mode == GEN_USAGE ) {
+				assertf( mut->expr_id, "unfilled expression id in generating candidate type" );
+				mut->formal_usage = next_usage_id;
+			} else {
+				assert(false);
+			}
+			idMap[ td->name ] = ast::TypeEnvKey( *mut );
+
+			td = mut;
 		}
 
-		void nextUsage() {
-			++next_usage_id;
-		}
+		return mutType;
+	}
 
-		const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
-			auto it = idMap.find( type->name );
-			if ( it == idMap.end() ) return type;
+	void closeLevel( const ast::FunctionType * type ) {
+		if ( type->forall.empty() ) return;
+		idMap.endScope();
+	}
+};
 
-			// Unconditionally mutate because map will *always* have different name.
-			ast::TypeInstType * mut = ast::shallowCopy( type );
-			// Reconcile base node since some copies might have been made.
-			mut->base = it->second.base;
-			mut->formal_usage = it->second.formal_usage;
-			mut->expr_id = it->second.expr_id;
-			return mut;
-		}
+// Global State:
+RenamingData renaming;
 
-		const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
-			if ( type->forall.empty() ) return type;
-			idMap.beginScope();
+struct RenameVars final : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
+	RenameMode mode;
 
-			// Load new names from this forall clause and perform renaming.
-			auto mutType = ast::shallowCopy( type );
-			// assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
-			for ( auto & td : mutType->forall ) {
-				auto mut = ast::shallowCopy( td.get() );
-				// assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
+	const ast::FunctionType * previsit( const ast::FunctionType * type ) {
+		return renaming.openLevel( type, mode );
+	}
 
-				if (mode == GEN_EXPR_ID) {
-					mut->expr_id = next_expr_id;
-					mut->formal_usage = -1;
-					++next_expr_id;
-				}
-				else if (mode == GEN_USAGE) {
-					assertf(mut->expr_id, "unfilled expression id in generating candidate type");
-					mut->formal_usage = next_usage_id;
-				}
-				else {
-					assert(false);
-				}
-				idMap[ td->name ] = ast::TypeEnvKey( *mut );
+	/*
+	const ast::StructInstType * previsit( const ast::StructInstType * type ) {
+		return renaming.openLevel( type );
+	}
+	const ast::UnionInstType * previsit( const ast::UnionInstType * type ) {
+		return renaming.openLevel( type );
+	}
+	const ast::TraitInstType * previsit( const ast::TraitInstType * type ) {
+		return renaming.openLevel( type );
+	}
+	*/
 
-				td = mut;
-			}
-
-			return mutType;
-		}
-
-		void closeLevel( const ast::FunctionType * type ) {
-			if ( type->forall.empty() ) return;
-			idMap.endScope();
-		}
-	};
-
-	// Global State:
-	RenamingData renaming;
-
-	struct RenameVars final : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
-		RenameMode mode;
-
-		const ast::FunctionType * previsit( const ast::FunctionType * type ) {
-			return renaming.openLevel( type, mode );
-		}
-
-		/*
-		const ast::StructInstType * previsit( const ast::StructInstType * type ) {
-			return renaming.openLevel( type );
-		}
-		const ast::UnionInstType * previsit( const ast::UnionInstType * type ) {
-			return renaming.openLevel( type );
-		}
-		const ast::TraitInstType * previsit( const ast::TraitInstType * type ) {
-			return renaming.openLevel( type );
-		}
-		*/
-
-		const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
-			if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type
-			return renaming.rename( type );
-		}
-		void postvisit( const ast::FunctionType * type ) {
-			renaming.closeLevel( type );
-		}
-	};
+	const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
+		// Do not rename an actual type.
+		if ( mode == GEN_USAGE && !type->formal_usage ) return type;
+		return renaming.rename( type );
+	}
+	void postvisit( const ast::FunctionType * type ) {
+		renaming.closeLevel( type );
+	}
+};
 
 } // namespace
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/ResolvExpr/Unify.cc	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -47,325 +47,300 @@
 namespace ResolvExpr {
 
-	bool typesCompatible(
-			const ast::Type * first, const ast::Type * second,
-			const ast::TypeEnvironment & env ) {
-		ast::TypeEnvironment newEnv;
-		ast::OpenVarSet open, closed;
-		ast::AssertionSet need, have;
-
-		ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
-		env.apply( newFirst );
-		env.apply( newSecond );
-
-		// findOpenVars( newFirst, open, closed, need, have, FirstClosed );
-		findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
-
-		return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
-	}
-
-	bool typesCompatibleIgnoreQualifiers(
-			const ast::Type * first, const ast::Type * second,
-			const ast::TypeEnvironment & env ) {
-		ast::TypeEnvironment newEnv;
-		ast::OpenVarSet open;
-		ast::AssertionSet need, have;
-
-		ast::Type * newFirst  = shallowCopy( first  );
-		ast::Type * newSecond = shallowCopy( second );
-
-		newFirst ->qualifiers = {};
-		newSecond->qualifiers = {};
-		ast::ptr< ast::Type > t1_(newFirst );
-		ast::ptr< ast::Type > t2_(newSecond);
-
-		ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
-		ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
-
-		return unifyExact(
-			subFirst,
-			subSecond,
-			newEnv, need, have, open, noWiden() );
-	}
-
-	namespace {
-				/// Replaces ttype variables with their bound types.
-		/// If this isn't done when satifying ttype assertions, then argument lists can have
-		/// different size and structure when they should be compatible.
-		struct TtypeExpander : public ast::WithShortCircuiting, public ast::PureVisitor {
-			ast::TypeEnvironment & tenv;
-
-			TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {}
-
-			const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
-				if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
-					// expand ttype parameter into its actual type
-					if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
-						return clz->bound;
-					}
+bool typesCompatible(
+		const ast::Type * first, const ast::Type * second,
+		const ast::TypeEnvironment & env ) {
+	ast::TypeEnvironment newEnv;
+	ast::OpenVarSet open, closed;
+	ast::AssertionSet need, have;
+
+	ast::ptr<ast::Type> newFirst( first ), newSecond( second );
+	env.apply( newFirst );
+	env.apply( newSecond );
+
+	// findOpenVars( newFirst, open, closed, need, have, FirstClosed );
+	findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
+
+	return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
+}
+
+bool typesCompatibleIgnoreQualifiers(
+		const ast::Type * first, const ast::Type * second,
+		const ast::TypeEnvironment & env ) {
+	ast::TypeEnvironment newEnv;
+	ast::OpenVarSet open;
+	ast::AssertionSet need, have;
+
+	ast::Type * newFirst  = shallowCopy( first  );
+	ast::Type * newSecond = shallowCopy( second );
+
+	newFirst ->qualifiers = {};
+	newSecond->qualifiers = {};
+	ast::ptr< ast::Type > t1_(newFirst );
+	ast::ptr< ast::Type > t2_(newSecond);
+
+	ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
+	ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
+
+	return unifyExact(
+		subFirst,
+		subSecond,
+		newEnv, need, have, open, noWiden() );
+}
+
+namespace {
+	/// Replaces ttype variables with their bound types.
+	/// If this isn't done when satifying ttype assertions, then argument lists can have
+	/// different size and structure when they should be compatible.
+	struct TtypeExpander : public ast::WithShortCircuiting, public ast::PureVisitor {
+		ast::TypeEnvironment & tenv;
+
+		TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {}
+
+		const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
+			if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
+				// expand ttype parameter into its actual type
+				if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
+					return clz->bound;
 				}
-				return typeInst;
 			}
-		};
-	}
-
-	std::vector< ast::ptr< ast::Type > > flattenList(
-		const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
+			return typeInst;
+		}
+	};
+}
+
+std::vector< ast::ptr< ast::Type > > flattenList(
+	const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
+) {
+	std::vector< ast::ptr< ast::Type > > dst;
+	dst.reserve( src.size() );
+	for ( const auto & d : src ) {
+		ast::Pass<TtypeExpander> expander( env );
+		// TtypeExpander pass is impure (may mutate nodes in place)
+		// need to make nodes shared to prevent accidental mutation
+		ast::ptr<ast::Type> dc = d->accept(expander);
+		auto types = flatten( dc );
+		for ( ast::ptr< ast::Type > & t : types ) {
+			// outermost const, volatile, _Atomic qualifiers in parameters should not play
+			// a role in the unification of function types, since they do not determine
+			// whether a function is callable.
+			// NOTE: **must** consider at least mutex qualifier, since functions can be
+			// overloaded on outermost mutex and a mutex function has different
+			// requirements than a non-mutex function
+			remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
+			dst.emplace_back( t );
+		}
+	}
+	return dst;
+}
+
+// Unification of Expressions
+//
+// Boolean outcome (obvious):  Are they basically spelled the same?
+// Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
+//
+// Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
+// where the VAREXPR are meant as notational metavariables representing the fact that unification always
+// sees distinct ast::VariableExpr objects at these positions
+
+static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
+	ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+	WidenMode widen );
+
+class UnifyExpr final : public ast::WithShortCircuiting {
+	const ast::Expr * e2;
+	ast::TypeEnvironment & tenv;
+	ast::AssertionSet & need;
+	ast::AssertionSet & have;
+	const ast::OpenVarSet & open;
+	WidenMode widen;
+public:
+	bool result;
+
+private:
+
+	void tryMatchOnStaticValue( const ast::Expr * e1 ) {
+		Evaluation r1 = eval(e1);
+		Evaluation r2 = eval(e2);
+
+		if ( !r1.hasKnownValue ) return;
+		if ( !r2.hasKnownValue ) return;
+
+		if ( r1.knownValue != r2.knownValue ) return;
+
+		visit_children = false;
+		result = true;
+	}
+
+public:
+
+	void previsit( const ast::Node * ) { assert(false); }
+
+	void previsit( const ast::Expr * e1 ) {
+		tryMatchOnStaticValue( e1 );
+		visit_children = false;
+	}
+
+	void previsit( const ast::CastExpr * e1 ) {
+		tryMatchOnStaticValue( e1 );
+
+		if ( result ) {
+			assert( visit_children == false );
+		} else {
+			assert( visit_children == true );
+			visit_children = false;
+
+			auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
+			if ( !e2c ) return;
+
+			// inspect casts' target types
+			if ( !unifyExact(
+				e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
+
+			// inspect casts' inner expressions
+			result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
+		}
+	}
+
+	void previsit( const ast::VariableExpr * e1 ) {
+		tryMatchOnStaticValue( e1 );
+
+		if ( result ) {
+			assert( visit_children == false );
+		} else {
+			assert( visit_children == true );
+			visit_children = false;
+
+			auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
+			if ( !e2v ) return;
+
+			assert(e1->var);
+			assert(e2v->var);
+
+			// conservative: variable exprs match if their declarations are represented by the same C++ AST object
+			result = (e1->var == e2v->var);
+		}
+	}
+
+	void previsit( const ast::SizeofExpr * e1 ) {
+		tryMatchOnStaticValue( e1 );
+
+		if ( result ) {
+			assert( visit_children == false );
+		} else {
+			assert( visit_children == true );
+			visit_children = false;
+
+			auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
+			if ( !e2so ) return;
+
+			assert((e1->type != nullptr) ^ (e1->expr != nullptr));
+			assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
+			if ( !(e1->type && e2so->type) ) return;
+
+			// expression unification calls type unification (mutual recursion)
+			result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
+		}
+	}
+
+	UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
+		ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
+	: e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
+};
+
+static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
+	ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+	WidenMode widen ) {
+	assert( e1 && e2 );
+	return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
+}
+
+class Unify final : public ast::WithShortCircuiting {
+	const ast::Type * type2;
+	ast::TypeEnvironment & tenv;
+	ast::AssertionSet & need;
+	ast::AssertionSet & have;
+	const ast::OpenVarSet & open;
+	WidenMode widen;
+public:
+	static size_t traceId;
+	bool result;
+
+	Unify(
+		const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
+		ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
+	: type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
+	result(false) {}
+
+	void previsit( const ast::Node * ) { visit_children = false; }
+
+	void postvisit( const ast::VoidType * vt) {
+		result = dynamic_cast< const ast::VoidType * >( type2 )
+			|| tryToUnifyWithEnumValue(vt, type2, tenv, need, have, open, noWiden());
+		;
+	}
+
+	void postvisit( const ast::BasicType * basic ) {
+		if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
+			result = basic->kind == basic2->kind;
+		}
+		result = result || tryToUnifyWithEnumValue(basic, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::PointerType * pointer ) {
+		if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
+			result = unifyExact(
+				pointer->base, pointer2->base, tenv, need, have, open,
+				noWiden());
+		}
+		result = result || tryToUnifyWithEnumValue(pointer, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::ArrayType * array ) {
+		auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
+		if ( !array2 ) return;
+
+		if ( array->isVarLen != array2->isVarLen ) return;
+		if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
+
+		if ( array->dimension ) {
+			assert( array2->dimension );
+			// type unification calls expression unification (mutual recursion)
+			if ( !unify(array->dimension, array2->dimension,
+				tenv, need, have, open, widen) ) return;
+		}
+
+		result = unifyExact(
+			array->base, array2->base, tenv, need, have, open, noWiden())
+			|| tryToUnifyWithEnumValue(array, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::ReferenceType * ref ) {
+		if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
+			result = unifyExact(
+				ref->base, ref2->base, tenv, need, have, open, noWiden());
+		}
+	}
+
+private:
+
+	template< typename Iter >
+	static bool unifyTypeList(
+		Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
+		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
 	) {
-		std::vector< ast::ptr< ast::Type > > dst;
-		dst.reserve( src.size() );
-		for ( const auto & d : src ) {
-			ast::Pass<TtypeExpander> expander{ env };
-			// TtypeExpander pass is impure (may mutate nodes in place)
-			// need to make nodes shared to prevent accidental mutation
-			ast::ptr<ast::Type> dc = d->accept(expander);
-			auto types = flatten( dc );
-			for ( ast::ptr< ast::Type > & t : types ) {
-				// outermost const, volatile, _Atomic qualifiers in parameters should not play
-				// a role in the unification of function types, since they do not determine
-				// whether a function is callable.
-				// NOTE: **must** consider at least mutex qualifier, since functions can be
-				// overloaded on outermost mutex and a mutex function has different
-				// requirements than a non-mutex function
-				remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
-				dst.emplace_back( t );
-			}
-		}
-		return dst;
-	}
-
-	// Unification of Expressions
-	//
-	// Boolean outcome (obvious):  Are they basically spelled the same?
-	// Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
-	//
-	// Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
-	// where the VAREXPR are meant as notational metavariables representing the fact that unification always
-	// sees distinct ast::VariableExpr objects at these positions
-
-	static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
-		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
-		WidenMode widen );
-
-	class UnifyExpr final : public ast::WithShortCircuiting {
-		const ast::Expr * e2;
-		ast::TypeEnvironment & tenv;
-		ast::AssertionSet & need;
-		ast::AssertionSet & have;
-		const ast::OpenVarSet & open;
-		WidenMode widen;
-	public:
-		bool result;
-
-	private:
-
-		void tryMatchOnStaticValue( const ast::Expr * e1 ) {
-			Evaluation r1 = eval(e1);
-			Evaluation r2 = eval(e2);
-
-			if ( ! r1.hasKnownValue ) return;
-			if ( ! r2.hasKnownValue ) return;
-
-			if (r1.knownValue != r2.knownValue) return;
-
-			visit_children = false;
-			result = true;
-		}
-
-	public:
-
-		void previsit( const ast::Node * ) { assert(false); }
-
-		void previsit( const ast::Expr * e1 ) {
-			tryMatchOnStaticValue( e1 );
-			visit_children = false;
-		}
-
-		void previsit( const ast::CastExpr * e1 ) {
-			tryMatchOnStaticValue( e1 );
-
-			if (result) {
-				assert (visit_children == false);
-			} else {
-				assert (visit_children == true);
-				visit_children = false;
-
-				auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
-				if ( ! e2c ) return;
-
-				// inspect casts' target types
-				if ( ! unifyExact(
-					e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
-
-				// inspect casts' inner expressions
-				result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
-			}
-		}
-
-		void previsit( const ast::VariableExpr * e1 ) {
-			tryMatchOnStaticValue( e1 );
-
-			if (result) {
-				assert (visit_children == false);
-			} else {
-				assert (visit_children == true);
-				visit_children = false;
-
-				auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
-				if ( ! e2v ) return;
-
-				assert(e1->var);
-				assert(e2v->var);
-
-				// conservative: variable exprs match if their declarations are represented by the same C++ AST object
-				result = (e1->var == e2v->var);
-			}
-		}
-
-		void previsit( const ast::SizeofExpr * e1 ) {
-			tryMatchOnStaticValue( e1 );
-
-			if (result) {
-				assert (visit_children == false);
-			} else {
-				assert (visit_children == true);
-				visit_children = false;
-
-				auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
-				if ( ! e2so ) return;
-
-				assert((e1->type != nullptr) ^ (e1->expr != nullptr));
-				assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
-				if ( ! (e1->type && e2so->type) )  return;
-
-				// expression unification calls type unification (mutual recursion)
-				result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
-			}
-		}
-
-		UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
-			ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
-		: e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
-	};
-
-	static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
-		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
-		WidenMode widen ) {
-		assert( e1 && e2 );
-		return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
-	}
-
-	class Unify final : public ast::WithShortCircuiting {
-		const ast::Type * type2;
-		ast::TypeEnvironment & tenv;
-		ast::AssertionSet & need;
-		ast::AssertionSet & have;
-		const ast::OpenVarSet & open;
-		WidenMode widen;
-	public:
-		static size_t traceId;
-		bool result;
-
-		Unify(
-			const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
-			ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
-		: type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
-		result(false) {}
-
-		void previsit( const ast::Node * ) { visit_children = false; }
-
-		void postvisit( const ast::VoidType * vt) {
-			result = dynamic_cast< const ast::VoidType * >( type2 )
-				|| tryToUnifyWithEnumValue(vt, type2, tenv, need, have, open, noWiden());
-			;
-		}
-
-		void postvisit( const ast::BasicType * basic ) {
-			if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
-				result = basic->kind == basic2->kind;
-			}
-			result = result || tryToUnifyWithEnumValue(basic, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::PointerType * pointer ) {
-			if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
-				result = unifyExact(
-					pointer->base, pointer2->base, tenv, need, have, open,
-					noWiden());
-			}
-			result = result || tryToUnifyWithEnumValue(pointer, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::ArrayType * array ) {
-			auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
-			if ( ! array2 ) return;
-
-			if ( array->isVarLen != array2->isVarLen ) return;
-			if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
-
-			if ( array->dimension ) {
-				assert( array2->dimension );
-				// type unification calls expression unification (mutual recursion)
-				if ( ! unify(array->dimension, array2->dimension,
-				    tenv, need, have, open, widen) ) return;
-			}
-
-			result = unifyExact(
-				array->base, array2->base, tenv, need, have, open, noWiden())
-				|| tryToUnifyWithEnumValue(array, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::ReferenceType * ref ) {
-			if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
-				result = unifyExact(
-					ref->base, ref2->base, tenv, need, have, open, noWiden());
-			}
-		}
-
-	private:
-
-		template< typename Iter >
-		static bool unifyTypeList(
-			Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
-			ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
-		) {
-			while ( crnt1 != end1 && crnt2 != end2 ) {
-				const ast::Type * t1 = *crnt1;
-				const ast::Type * t2 = *crnt2;
-				bool isTuple1 = Tuples::isTtype( t1 );
-				bool isTuple2 = Tuples::isTtype( t2 );
-
-				// assumes here that ttype *must* be last parameter
-				if ( isTuple1 && ! isTuple2 ) {
-					// combine remainder of list2, then unify
-					return unifyExact(
-						t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
-						noWiden() );
-				} else if ( ! isTuple1 && isTuple2 ) {
-					// combine remainder of list1, then unify
-					return unifyExact(
-						tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
-						noWiden() );
-				}
-
-				if ( ! unifyExact(
-					t1, t2, env, need, have, open, noWiden() )
-				) return false;
-
-				++crnt1; ++crnt2;
-			}
-
-			// May get to the end of one argument list before the other. This is only okay if the
-			// other is a ttype
-			if ( crnt1 != end1 ) {
-				// try unifying empty tuple with ttype
-				const ast::Type * t1 = *crnt1;
-				if ( ! Tuples::isTtype( t1 ) ) return false;
+		while ( crnt1 != end1 && crnt2 != end2 ) {
+			const ast::Type * t1 = *crnt1;
+			const ast::Type * t2 = *crnt2;
+			bool isTuple1 = Tuples::isTtype( t1 );
+			bool isTuple2 = Tuples::isTtype( t2 );
+
+			// assumes here that ttype *must* be last parameter
+			if ( isTuple1 && !isTuple2 ) {
+				// combine remainder of list2, then unify
 				return unifyExact(
 					t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
 					noWiden() );
-			} else if ( crnt2 != end2 ) {
-				// try unifying empty tuple with ttype
-				const ast::Type * t2 = *crnt2;
-				if ( ! Tuples::isTtype( t2 ) ) return false;
+			} else if ( !isTuple1 && isTuple2 ) {
+				// combine remainder of list1, then unify
 				return unifyExact(
 					tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
@@ -373,383 +348,408 @@
 			}
 
-			return true;
-		}
-
-		static bool unifyTypeList(
-			const std::vector< ast::ptr< ast::Type > > & list1,
-			const std::vector< ast::ptr< ast::Type > > & list2,
-			ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-			const ast::OpenVarSet & open
-		) {
-			return unifyTypeList(
-				list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open);
-		}
-
-		static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
-			auto i = assns.find( assn );
-			if ( i != assns.end() ) {
-				i->second.isUsed = true;
+			if ( !unifyExact(
+				t1, t2, env, need, have, open, noWiden() )
+			) return false;
+
+			++crnt1; ++crnt2;
+		}
+
+		// May get to the end of one argument list before the other. This is only okay if the
+		// other is a ttype
+		if ( crnt1 != end1 ) {
+			// try unifying empty tuple with ttype
+			const ast::Type * t1 = *crnt1;
+			if ( !Tuples::isTtype( t1 ) ) return false;
+			return unifyExact(
+				t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
+				noWiden() );
+		} else if ( crnt2 != end2 ) {
+			// try unifying empty tuple with ttype
+			const ast::Type * t2 = *crnt2;
+			if ( !Tuples::isTtype( t2 ) ) return false;
+			return unifyExact(
+				tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
+				noWiden() );
+		}
+
+		return true;
+	}
+
+	static bool unifyTypeList(
+		const std::vector< ast::ptr< ast::Type > > & list1,
+		const std::vector< ast::ptr< ast::Type > > & list2,
+		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+		const ast::OpenVarSet & open
+	) {
+		return unifyTypeList(
+			list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open);
+	}
+
+	static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
+		auto i = assns.find( assn );
+		if ( i != assns.end() ) {
+			i->second.isUsed = true;
+		}
+	}
+
+	/// mark all assertions in `type` used in both `assn1` and `assn2`
+	static void markAssertions(
+		ast::AssertionSet & assn1, ast::AssertionSet & assn2,
+		const ast::FunctionType * type
+	) {
+		for ( auto & assert : type->assertions ) {
+			markAssertionSet( assn1, assert );
+			markAssertionSet( assn2, assert );
+		}
+	}
+
+	bool tryToUnifyWithEnumValue( const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
+		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+		WidenMode widen) {
+		if ( auto attrType2 = dynamic_cast<const ast::EnumAttrType *>(type2)) {
+			if (attrType2->attr == ast::EnumAttribute::Value) {
+				return unifyExact( type1, attrType2->instance->base->base, env, need, have, open,
+					widen);
+			} else if (attrType2->attr == ast::EnumAttribute::Posn) {
+				return unifyExact( type1, attrType2->instance, env, need, have, open, widen );
 			}
 		}
-
-		/// mark all assertions in `type` used in both `assn1` and `assn2`
-		static void markAssertions(
-			ast::AssertionSet & assn1, ast::AssertionSet & assn2,
-			const ast::FunctionType * type
-		) {
-			for ( auto & assert : type->assertions ) {
-				markAssertionSet( assn1, assert );
-				markAssertionSet( assn2, assert );
+		return false;
+	}
+
+public:
+	void postvisit( const ast::FunctionType * func ) {
+		auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
+		if ( !func2 ) return;
+
+		if ( func->isVarArgs != func2->isVarArgs ) return;
+
+		// Flatten the parameter lists for both functions so that tuple structure does not
+		// affect unification. Does not actually mutate function parameters.
+		auto params = flattenList( func->params, tenv );
+		auto params2 = flattenList( func2->params, tenv );
+
+		// sizes don't have to match if ttypes are involved; need to be more precise w.r.t.
+		// where the ttype is to prevent errors
+		if (
+			( params.size() != params2.size() || func->returns.size() != func2->returns.size() )
+			&& !func->isTtype()
+			&& !func2->isTtype()
+		) return;
+
+		if ( !unifyTypeList( params, params2, tenv, need, have, open ) ) return;
+		if ( !unifyTypeList(
+			func->returns, func2->returns, tenv, need, have, open ) ) return;
+
+		markAssertions( have, need, func );
+		markAssertions( have, need, func2 );
+
+		result = true;
+	}
+
+private:
+	// Returns: other, cast as XInstType
+	// Assigns this->result: whether types are compatible (up to generic parameters)
+	template< typename XInstType >
+	const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
+		// check that the other type is compatible and named the same
+		auto otherInst = dynamic_cast< const XInstType * >( other );
+		if ( otherInst && inst->name == otherInst->name ) {
+			this->result = otherInst;
+		}
+		return otherInst;
+	}
+
+	/// Creates a tuple type based on a list of TypeExpr
+	template< typename Iter >
+	static const ast::Type * tupleFromExprs(
+		const ast::TypeExpr * param, Iter & crnt, Iter end, ast::CV::Qualifiers qs
+	) {
+		std::vector< ast::ptr< ast::Type > > types;
+		do {
+			types.emplace_back( param->type );
+
+			++crnt;
+			if ( crnt == end ) break;
+			param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
+		} while(true);
+
+		return new ast::TupleType( std::move(types), qs );
+	}
+
+	template< typename XInstType >
+	void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
+		// check that other type is compatible and named the same
+		const XInstType * otherInst = handleRefType( inst, other );
+		if ( !this->result ) return;
+
+		// check that parameters of types unify, if any
+		const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
+		const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
+
+		auto it = params.begin();
+		auto jt = params2.begin();
+		for ( ; it != params.end() && jt != params2.end(); ++it, ++jt ) {
+			auto param = strict_dynamic_cast< const ast::TypeExpr * >( it->get() );
+			auto param2 = strict_dynamic_cast< const ast::TypeExpr * >( jt->get() );
+
+			ast::ptr< ast::Type > pty = param->type;
+			ast::ptr< ast::Type > pty2 = param2->type;
+
+			bool isTuple = Tuples::isTtype( pty );
+			bool isTuple2 = Tuples::isTtype( pty2 );
+
+			if ( isTuple && isTuple2 ) {
+				++it; ++jt;  // skip ttype parameters before break
+			} else if ( isTuple ) {
+				// bundle remaining params into tuple
+				pty2 = tupleFromExprs( param2, jt, params2.end(), pty->qualifiers );
+				++it;  // skip ttype parameter for break
+			} else if ( isTuple2 ) {
+				// bundle remaining params into tuple
+				pty = tupleFromExprs( param, it, params.end(), pty2->qualifiers );
+				++jt;  // skip ttype parameter for break
 			}
-		}
-
-		bool tryToUnifyWithEnumValue( const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
-			ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
-			WidenMode widen) {
-			if ( auto attrType2 = dynamic_cast<const ast::EnumAttrType *>(type2)) {
-				if (attrType2->attr == ast::EnumAttribute::Value) {
-					return unifyExact( type1, attrType2->instance->base->base, env, need, have, open,
-						widen);
-				} else if (attrType2->attr == ast::EnumAttribute::Posn) {
-					return unifyExact( type1, attrType2->instance, env, need, have, open, widen );
-				}
+
+			if ( !unifyExact(
+					pty, pty2, tenv, need, have, open, noWiden() ) ) {
+				result = false;
+				return;
 			}
-			return false;
-		}
-
-	public:
-		void postvisit( const ast::FunctionType * func ) {
-			auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
-			if ( ! func2 ) return;
-
-			if ( func->isVarArgs != func2->isVarArgs ) return;
-
-			// Flatten the parameter lists for both functions so that tuple structure does not
-			// affect unification. Does not actually mutate function parameters.
-			auto params = flattenList( func->params, tenv );
-			auto params2 = flattenList( func2->params, tenv );
-
-			// sizes don't have to match if ttypes are involved; need to be more precise w.r.t.
-			// where the ttype is to prevent errors
-			if (
-				( params.size() != params2.size() || func->returns.size() != func2->returns.size() )
-				&& ! func->isTtype()
-				&& ! func2->isTtype()
-			) return;
-
-			if ( ! unifyTypeList( params, params2, tenv, need, have, open ) ) return;
-			if ( ! unifyTypeList(
-				func->returns, func2->returns, tenv, need, have, open ) ) return;
-
-			markAssertions( have, need, func );
-			markAssertions( have, need, func2 );
-
-			result = true;
-		}
-
-	private:
-		// Returns: other, cast as XInstType
-		// Assigns this->result: whether types are compatible (up to generic parameters)
-		template< typename XInstType >
-		const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
-			// check that the other type is compatible and named the same
-			auto otherInst = dynamic_cast< const XInstType * >( other );
-			if (otherInst && inst->name == otherInst->name) 
-				this->result = otherInst;
-			return otherInst;
-		}
-
-		/// Creates a tuple type based on a list of TypeExpr
-		template< typename Iter >
-		static const ast::Type * tupleFromExprs(
-			const ast::TypeExpr * param, Iter & crnt, Iter end, ast::CV::Qualifiers qs
-		) {
-			std::vector< ast::ptr< ast::Type > > types;
-			do {
-				types.emplace_back( param->type );
-
-				++crnt;
-				if ( crnt == end ) break;
-				param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
-			} while(true);
-
-			return new ast::TupleType{ std::move(types), qs };
-		}
-
-		template< typename XInstType >
-		void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
-			// check that other type is compatible and named the same
-			const XInstType * otherInst = handleRefType( inst, other );
-			if ( ! this->result ) return;
-
-			// check that parameters of types unify, if any
-			const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
-			const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
-
-			auto it = params.begin();
-			auto jt = params2.begin();
-			for ( ; it != params.end() && jt != params2.end(); ++it, ++jt ) {
-				auto param = strict_dynamic_cast< const ast::TypeExpr * >( it->get() );
-				auto param2 = strict_dynamic_cast< const ast::TypeExpr * >( jt->get() );
-
-				ast::ptr< ast::Type > pty = param->type;
-				ast::ptr< ast::Type > pty2 = param2->type;
-
-				bool isTuple = Tuples::isTtype( pty );
-				bool isTuple2 = Tuples::isTtype( pty2 );
-
-				if ( isTuple && isTuple2 ) {
-					++it; ++jt;  // skip ttype parameters before break
-				} else if ( isTuple ) {
-					// bundle remaining params into tuple
-					pty2 = tupleFromExprs( param2, jt, params2.end(), pty->qualifiers );
-					++it;  // skip ttype parameter for break
-				} else if ( isTuple2 ) {
-					// bundle remaining params into tuple
-					pty = tupleFromExprs( param, it, params.end(), pty2->qualifiers );
-					++jt;  // skip ttype parameter for break
-				}
-
-				if ( ! unifyExact(
-						pty, pty2, tenv, need, have, open, noWiden() ) ) {
-					result = false;
-					return;
-				}
-
-				// ttype parameter should be last
-				if ( isTuple || isTuple2 ) break;
+
+			// ttype parameter should be last
+			if ( isTuple || isTuple2 ) break;
+		}
+		result = it == params.end() && jt == params2.end();
+	}
+
+public:
+	void postvisit( const ast::StructInstType * aggrType ) {
+		handleGenericRefType( aggrType, type2 );
+		result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::UnionInstType * aggrType ) {
+		handleGenericRefType( aggrType, type2 );
+		result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::EnumInstType * aggrType ) {
+		handleRefType( aggrType, type2 );
+		result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::EnumAttrType * enumAttr ) {
+		// Lazy approach for now
+		if ( auto otherPos = dynamic_cast< const ast::EnumAttrType *>( type2 ) ) {
+			if ( enumAttr->match(otherPos) ) {
+				result = otherPos;
 			}
-			result = it == params.end() && jt == params2.end();
-		}
-
-	public:
-		void postvisit( const ast::StructInstType * aggrType ) {
-			handleGenericRefType( aggrType, type2 );
-			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::UnionInstType * aggrType ) {
-			handleGenericRefType( aggrType, type2 );
-			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::EnumInstType * aggrType ) {
-			handleRefType( aggrType, type2 );
-			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::EnumAttrType * enumAttr ) {
-			// Lazy approach for now
-			if ( auto otherPos = dynamic_cast< const ast::EnumAttrType *>(type2) ) {
-			    if ( enumAttr->match(otherPos) ) {
-				    result = otherPos;
-			    }
-            }  
-		}
-
-		void postvisit( const ast::TraitInstType * aggrType ) {
-			handleRefType( aggrType, type2 );
-			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::TypeInstType * typeInst ) {
-			// assert( open.find( *typeInst ) == open.end() );
-			auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
-			if ( otherInst && typeInst->name == otherInst->name ) {
-				this->result = otherInst;
+		}
+	}
+
+	void postvisit( const ast::TraitInstType * aggrType ) {
+		handleRefType( aggrType, type2 );
+		result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::TypeInstType * typeInst ) {
+		// assert( open.find( *typeInst ) == open.end() );
+		auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
+		if ( otherInst && typeInst->name == otherInst->name ) {
+			this->result = otherInst;
+		}
+		result = result || tryToUnifyWithEnumValue(typeInst, type2, tenv, need, have, open, noWiden());
+	}
+
+private:
+	/// Creates a tuple type based on a list of Type
+	static bool unifyList(
+		const std::vector< ast::ptr< ast::Type > > & list1,
+		const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
+		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
+	) {
+		auto crnt1 = list1.begin();
+		auto crnt2 = list2.begin();
+		while ( crnt1 != list1.end() && crnt2 != list2.end() ) {
+			const ast::Type * t1 = *crnt1;
+			const ast::Type * t2 = *crnt2;
+			bool isTuple1 = Tuples::isTtype( t1 );
+			bool isTuple2 = Tuples::isTtype( t2 );
+
+			// assumes ttype must be last parameter
+			if ( isTuple1 && !isTuple2 ) {
+				// combine entirety of list2, then unify
+				return unifyExact(
+					t1, tupleFromTypes( list2 ), env, need, have, open,
+					noWiden() );
+			} else if ( !isTuple1 && isTuple2 ) {
+				// combine entirety of list1, then unify
+				return unifyExact(
+					tupleFromTypes( list1 ), t2, env, need, have, open,
+					noWiden() );
 			}
-			result = result || tryToUnifyWithEnumValue(typeInst, type2, tenv, need, have, open, noWiden());
-		}
-
-	private:
-		/// Creates a tuple type based on a list of Type
-
-		static bool unifyList(
-			const std::vector< ast::ptr< ast::Type > > & list1,
-			const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
-			ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
-		) {
-			auto crnt1 = list1.begin();
-			auto crnt2 = list2.begin();
-			while ( crnt1 != list1.end() && crnt2 != list2.end() ) {
-				const ast::Type * t1 = *crnt1;
-				const ast::Type * t2 = *crnt2;
-				bool isTuple1 = Tuples::isTtype( t1 );
-				bool isTuple2 = Tuples::isTtype( t2 );
-
-				// assumes ttype must be last parameter
-				if ( isTuple1 && ! isTuple2 ) {
-					// combine entirety of list2, then unify
-					return unifyExact(
-						t1, tupleFromTypes( list2 ), env, need, have, open,
-						noWiden() );
-				} else if ( ! isTuple1 && isTuple2 ) {
-					// combine entirety of list1, then unify
-					return unifyExact(
-						tupleFromTypes( list1 ), t2, env, need, have, open,
-						noWiden() );
-				}
-
-				if ( ! unifyExact(
-					t1, t2, env, need, have, open, noWiden() )
-				) return false;
-
-				++crnt1; ++crnt2;
-			}
-
-			if ( crnt1 != list1.end() ) {
-				// try unifying empty tuple type with ttype
-				const ast::Type * t1 = *crnt1;
-				if ( ! Tuples::isTtype( t1 ) ) return false;
-				// xxx - this doesn't generate an empty tuple, contrary to comment; both ported
-				// from Rob's code
-				return unifyExact(
-						t1, tupleFromTypes( list2 ), env, need, have, open,
-						noWiden() );
-			} else if ( crnt2 != list2.end() ) {
-				// try unifying empty tuple with ttype
-				const ast::Type * t2 = *crnt2;
-				if ( ! Tuples::isTtype( t2 ) ) return false;
-				// xxx - this doesn't generate an empty tuple, contrary to comment; both ported
-				// from Rob's code
-				return unifyExact(
-						tupleFromTypes( list1 ), t2, env, need, have, open,
-						noWiden() );
-			}
-
-			return true;
-		}
-
-	public:
-		void postvisit( const ast::TupleType * tuple ) {
-			auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
-			if ( ! tuple2 ) return;
-
-			ast::Pass<TtypeExpander> expander{ tenv };
-
-			const ast::Type * flat = tuple->accept( expander );
-			const ast::Type * flat2 = tuple2->accept( expander );
-
-			auto types = flatten( flat );
-			auto types2 = flatten( flat2 );
-
-			result = unifyList( types, types2, tenv, need, have, open )
-				|| tryToUnifyWithEnumValue(tuple, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::VarArgsType * vat) {
-			result = dynamic_cast< const ast::VarArgsType * >( type2 )
-				|| tryToUnifyWithEnumValue(vat, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::ZeroType * zt) {
-			result = dynamic_cast< const ast::ZeroType * >( type2 )
-				|| tryToUnifyWithEnumValue(zt, type2, tenv, need, have, open, noWiden());
-		}
-
-		void postvisit( const ast::OneType * ot) {
-			result = dynamic_cast< const ast::OneType * >( type2 )
-				|| tryToUnifyWithEnumValue(ot, type2, tenv, need, have, open, noWiden());
-		}
-	};
-
-	// size_t Unify::traceId = Stats::Heap::new_stacktrace_id("Unify");
-
-	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
-	) {
-		ast::ptr<ast::Type> common;
-		return unify( type1, type2, env, need, have, open, 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, ast::ptr<ast::Type> & common
-	) {
-		ast::OpenVarSet closed;
-		// findOpenVars( type1, open, closed, need, have, FirstClosed );
-		findOpenVars( type2, open, closed, need, have, env, FirstOpen );
-		return unifyInexact(
-			type1, type2, env, need, have, open, WidenMode{ true, true }, common );
-	}
-
-	bool unifyExact(
-			const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
-			ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
-			WidenMode widen
-	) {
-		if ( type1->qualifiers != type2->qualifiers ) return false;
-
-		auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
-		auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
-		bool isopen1 = var1 && env.lookup(*var1);
-		bool isopen2 = var2 && env.lookup(*var2);
-
-		if ( isopen1 && isopen2 ) {
-			if ( var1->base->kind != var2->base->kind ) return false;
-			return env.bindVarToVar(
-				var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
-				open, widen );
-		} else if ( isopen1 ) {
-			return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
-		} else if ( isopen2 ) {
-			return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
-		} else {
-			return ast::Pass<Unify>::read(
-				type1, type2, env, need, have, open, widen );
-		}
-	}
-
-	bool unifyInexact(
-			const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
-			ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-			const ast::OpenVarSet & open, WidenMode widen,
-			ast::ptr<ast::Type> & common
-	) {
-		ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
-
-		// force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
-		// type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
-		ast::Type * t1 = shallowCopy(type1.get());
-		ast::Type * t2 = shallowCopy(type2.get());
-		t1->qualifiers = {};
-		t2->qualifiers = {};
-		ast::ptr< ast::Type > t1_(t1);
-		ast::ptr< ast::Type > t2_(t2);
-
-		if ( unifyExact( t1, t2, env, need, have, open, widen ) ) {
-			// if exact unification on unqualified types, try to merge qualifiers
-			if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
-				t1->qualifiers = q1 | q2;
-				common = t1;
-				return true;
-			} else {
-				return false;
-			}
-
-		} else if (( common = commonType( t1, t2, env, need, have, open, widen ))) {
-			// no exact unification, but common type
-			auto c = shallowCopy(common.get());
-			c->qualifiers = q1 | q2;
-			common = c;
+
+			if ( !unifyExact(
+				t1, t2, env, need, have, open, noWiden() )
+			) return false;
+
+			++crnt1; ++crnt2;
+		}
+
+		if ( crnt1 != list1.end() ) {
+			// try unifying empty tuple type with ttype
+			const ast::Type * t1 = *crnt1;
+			if ( !Tuples::isTtype( t1 ) ) return false;
+			// xxx - this doesn't generate an empty tuple, contrary to comment; both ported
+			// from Rob's code
+			return unifyExact(
+					t1, tupleFromTypes( list2 ), env, need, have, open,
+					noWiden() );
+		} else if ( crnt2 != list2.end() ) {
+			// try unifying empty tuple with ttype
+			const ast::Type * t2 = *crnt2;
+			if ( !Tuples::isTtype( t2 ) ) return false;
+			// xxx - this doesn't generate an empty tuple, contrary to comment; both ported
+			// from Rob's code
+			return unifyExact(
+					tupleFromTypes( list1 ), t2, env, need, have, open,
+					noWiden() );
+		}
+
+		return true;
+	}
+
+public:
+	void postvisit( const ast::TupleType * tuple ) {
+		auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
+		if ( ! tuple2 ) return;
+
+		ast::Pass<TtypeExpander> expander{ tenv };
+
+		const ast::Type * flat = tuple->accept( expander );
+		const ast::Type * flat2 = tuple2->accept( expander );
+
+		auto types = flatten( flat );
+		auto types2 = flatten( flat2 );
+
+		result = unifyList( types, types2, tenv, need, have, open )
+			|| tryToUnifyWithEnumValue(tuple, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::VarArgsType * vat) {
+		result = dynamic_cast< const ast::VarArgsType * >( type2 )
+			|| tryToUnifyWithEnumValue(vat, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::ZeroType * zt) {
+		result = dynamic_cast< const ast::ZeroType * >( type2 )
+			|| tryToUnifyWithEnumValue(zt, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::OneType * ot) {
+		result = dynamic_cast< const ast::OneType * >( type2 )
+			|| tryToUnifyWithEnumValue(ot, type2, tenv, need, have, open, noWiden());
+	}
+};
+
+// size_t Unify::traceId = Stats::Heap::new_stacktrace_id("Unify");
+
+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
+) {
+	ast::ptr<ast::Type> common;
+	return unify( type1, type2, env, need, have, open, 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, ast::ptr<ast::Type> & common
+) {
+	ast::OpenVarSet closed;
+	// findOpenVars( type1, open, closed, need, have, FirstClosed );
+	findOpenVars( type2, open, closed, need, have, env, FirstOpen );
+	return unifyInexact(
+		type1, type2, env, need, have, open, WidenMode{ true, true }, common );
+}
+
+bool unifyExact(
+		const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
+		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+		WidenMode widen
+) {
+	if ( type1->qualifiers != type2->qualifiers ) return false;
+
+	auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
+	auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
+	bool isopen1 = var1 && env.lookup(*var1);
+	bool isopen2 = var2 && env.lookup(*var2);
+
+	if ( isopen1 && isopen2 ) {
+		if ( var1->base->kind != var2->base->kind ) return false;
+		return env.bindVarToVar(
+			var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
+			open, widen );
+	} else if ( isopen1 ) {
+		return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
+	} else if ( isopen2 ) {
+		return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
+	} else {
+		return ast::Pass<Unify>::read(
+			type1, type2, env, need, have, open, widen );
+	}
+}
+
+bool unifyInexact(
+		const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
+		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+		const ast::OpenVarSet & open, WidenMode widen,
+		ast::ptr<ast::Type> & common
+) {
+	ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
+
+	// force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
+	// type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
+	ast::Type * t1 = shallowCopy(type1.get());
+	ast::Type * t2 = shallowCopy(type2.get());
+	t1->qualifiers = {};
+	t2->qualifiers = {};
+	ast::ptr< ast::Type > t1_(t1);
+	ast::ptr< ast::Type > t2_(t2);
+
+	if ( unifyExact( t1, t2, env, need, have, open, widen ) ) {
+		// if exact unification on unqualified types, try to merge qualifiers
+		if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
+			t1->qualifiers = q1 | q2;
+			common = t1;
 			return true;
 		} else {
 			return false;
 		}
-	}
-
-	ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
-		if ( func->returns.empty() ) return new ast::VoidType{};
-		if ( func->returns.size() == 1 ) return func->returns[0];
-
-		std::vector<ast::ptr<ast::Type>> tys;
-		for ( const auto & decl : func->returns ) {
-			tys.emplace_back( decl );
-		}
-		return new ast::TupleType{ std::move(tys) };
-	}
+	} else if (( common = commonType( t1, t2, env, need, have, open, widen ))) {
+		// no exact unification, but common type
+		auto c = shallowCopy(common.get());
+		c->qualifiers = q1 | q2;
+		common = c;
+		return true;
+	} else {
+		return false;
+	}
+}
+
+ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
+	if ( func->returns.empty() ) return new ast::VoidType();
+	if ( func->returns.size() == 1 ) return func->returns[0];
+
+	std::vector<ast::ptr<ast::Type>> tys;
+	for ( const auto & decl : func->returns ) {
+		tys.emplace_back( decl );
+	}
+	return new ast::TupleType( std::move(tys) );
+}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/typeops.h
===================================================================
--- src/ResolvExpr/typeops.h	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/ResolvExpr/typeops.h	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -21,73 +21,75 @@
 
 namespace ResolvExpr {
-	class TypeEnvironment;
 
-	// combos: takes a list of sets and returns a set of lists representing every possible way of forming a list by
-	// picking one element out of each set
-	template< typename InputIterator, typename OutputIterator >
-	void combos( InputIterator begin, InputIterator end, OutputIterator out ) {
-		typedef typename InputIterator::value_type SetType;
-		typedef typename std::vector< typename SetType::value_type > ListType;
+class TypeEnvironment;
 
-		if ( begin == end )	{
-			*out++ = ListType();
-			return;
-		} // if
+// combos: takes a list of sets and returns a set of lists representing every possible way of forming a list by
+// picking one element out of each set
+template< typename InputIterator, typename OutputIterator >
+void combos( InputIterator begin, InputIterator end, OutputIterator out ) {
+	typedef typename InputIterator::value_type SetType;
+	typedef typename std::vector< typename SetType::value_type > ListType;
 
-		InputIterator current = begin;
-		begin++;
+	if ( begin == end )	{
+		*out++ = ListType();
+		return;
+	} // if
 
-		std::vector< ListType > recursiveResult;
-		combos( begin, end, back_inserter( recursiveResult ) );
+	InputIterator current = begin;
+	begin++;
 
-		for ( const auto& i : recursiveResult ) for ( const auto& j : *current ) {
-			ListType result;
-			std::back_insert_iterator< ListType > inserter = back_inserter( result );
-			*inserter++ = j;
-			std::copy( i.begin(), i.end(), inserter );
-			*out++ = result;
+	std::vector< ListType > recursiveResult;
+	combos( begin, end, back_inserter( recursiveResult ) );
+
+	for ( const auto& i : recursiveResult ) for ( const auto& j : *current ) {
+		ListType result;
+		std::back_insert_iterator< ListType > inserter = back_inserter( result );
+		*inserter++ = j;
+		std::copy( i.begin(), i.end(), inserter );
+		*out++ = result;
+	}
+}
+
+/// Flatten tuple type into existing list of types.
+inline void flatten(
+	const ast::Type * type, std::vector< ast::ptr< ast::Type > > & out
+) {
+	if ( auto tupleType = dynamic_cast< const ast::TupleType * >( type ) ) {
+		for ( const ast::Type * t : tupleType->types ) {
+			flatten( t, out );
 		}
+	} else {
+		out.emplace_back( type );
+	}
+}
+
+/// Flatten tuple type into list of types.
+inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {
+	std::vector< ast::ptr< ast::Type > > out;
+	out.reserve( type->size() );
+	flatten( type, out );
+	return out;
+}
+
+template< typename Iter >
+const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
+	std::vector< ast::ptr< ast::Type > > types;
+	while ( crnt != end ) {
+		// it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
+		// that this results in a flat tuple
+		flatten( *crnt, types );
+
+		++crnt;
 	}
 
-	/// flatten tuple type into existing list of types
-	inline void flatten(
-		const ast::Type * type, std::vector< ast::ptr< ast::Type > > & out
-	) {
-		if ( auto tupleType = dynamic_cast< const ast::TupleType * >( type ) ) {
-			for ( const ast::Type * t : tupleType->types ) {
-				flatten( t, out );
-			}
-		} else {
-			out.emplace_back( type );
-		}
-	}
+	return new ast::TupleType( std::move(types) );
+}
 
-	/// flatten tuple type into list of types
-	inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {
-		std::vector< ast::ptr< ast::Type > > out;
-		out.reserve( type->size() );
-		flatten( type, out );
-		return out;
-	}
+inline const ast::Type * tupleFromTypes(
+	const std::vector< ast::ptr< ast::Type > > & tys
+) {
+	return tupleFromTypes( tys.begin(), tys.end() );
+}
 
-	template< typename Iter >
-	const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
-		std::vector< ast::ptr< ast::Type > > types;
-		while ( crnt != end ) {
-			// it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
-			// that this results in a flat tuple
-			flatten( *crnt, types );
-
-			++crnt;
-		}
-
-		return new ast::TupleType{ std::move(types) };
-	}
-
-	inline const ast::Type * tupleFromTypes(
-		const std::vector< ast::ptr< ast::Type > > & tys
-	) {
-		return tupleFromTypes( tys.begin(), tys.end() );
-	}
 } // namespace ResolvExpr
 
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/SymTab/Mangler.cc	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -283,16 +283,16 @@
 	postvisit( enumAttr->instance );
 	// mangleName += "_pos";
-    switch ( enumAttr->attr )
-    {
-        case ast::EnumAttribute::Label:
-            mangleName += "_label_";
-            break;
-        case ast::EnumAttribute::Posn:
+	switch ( enumAttr->attr )
+	{
+		case ast::EnumAttribute::Label:
+			mangleName += "_label_";
+			break;
+		case ast::EnumAttribute::Posn:
 			mangleName += "_posn_";
-            break;
-        case ast::EnumAttribute::Value:
-            mangleName += "_value_";
-            break;
-    }
+			break;
+		case ast::EnumAttribute::Value:
+			mangleName += "_value_";
+			break;
+	}
 
 }
Index: src/Validate/ForallPointerDecay.hpp
===================================================================
--- src/Validate/ForallPointerDecay.hpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Validate/ForallPointerDecay.hpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -39,5 +39,5 @@
 /// Expand all traits in an assertion list.
 std::vector<ast::ptr<ast::DeclWithType>> expandAssertions(
-        std::vector<ast::ptr<ast::DeclWithType>> const & );
+		std::vector<ast::ptr<ast::DeclWithType>> const & );
 
 }
Index: src/Validate/HoistStruct.cpp
===================================================================
--- src/Validate/HoistStruct.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Validate/HoistStruct.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -149,20 +149,20 @@
 template<typename InstType>
 InstType const * HoistStructCore::preCollectionInstType( InstType const * type ) {
-    if ( !type->base->parent ) return type;
-    if ( type->base->params.empty() ) return type;
-
-    InstType * mut = ast::mutate( type );
-    ast::AggregateDecl const * parent =
-        commonParent( this->parent, mut->base->parent );
-    assert( parent );
-
-    std::vector<ast::ptr<ast::Expr>> args;
-    for ( const ast::ptr<ast::TypeDecl> & param : parent->params ) {
-        args.emplace_back( new ast::TypeExpr( param->location,
-            new ast::TypeInstType( param )
-        ) );
-    }
-    spliceBegin( mut->params, args );
-    return mut;
+	if ( !type->base->parent ) return type;
+	if ( type->base->params.empty() ) return type;
+
+	InstType * mut = ast::mutate( type );
+	ast::AggregateDecl const * parent =
+		commonParent( this->parent, mut->base->parent );
+	assert( parent );
+
+	std::vector<ast::ptr<ast::Expr>> args;
+	for ( const ast::ptr<ast::TypeDecl> & param : parent->params ) {
+		args.emplace_back( new ast::TypeExpr( param->location,
+			new ast::TypeInstType( param )
+		) );
+	}
+	spliceBegin( mut->params, args );
+	return mut;
 }
 
Index: src/Validate/ImplementEnumFunc.cpp
===================================================================
--- src/Validate/ImplementEnumFunc.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Validate/ImplementEnumFunc.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -8,285 +8,282 @@
 namespace {
 class EnumAttrFuncGenerator {
-    const ast::EnumDecl* decl;
-    const ast::EnumInstType* instType;
-    // const ast::EnumAttrType* attrType;
-    unsigned int functionNesting;
-    ast::Linkage::Spec proto_linkage;
-
-   public:
-    std::list<ast::ptr<ast::Decl>> forwards;
-    std::list<ast::ptr<ast::Decl>> definitions;
-
-    void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
-
-    EnumAttrFuncGenerator(const ast::EnumDecl* decl,
-                          const ast::EnumInstType* instType,
-                          // const ast::EnumAttrType* enumAttrType,
-                          unsigned int functionNesting)
-        : decl(decl),
-          instType{instType},
-          // attrType{enumAttrType},
-          functionNesting{functionNesting},
-          proto_linkage{ast::Linkage::Cforall} {}
-
-    void genAttrFunctions();
-    void genSuccPredPosn();
-    void genSuccPredDecl();
-
-    void appendReturnThis(ast::FunctionDecl* decl) {
-        assert(1 <= decl->params.size());
-        assert(1 == decl->returns.size());
-        assert(decl->stmts);
-
-        const CodeLocation& location = (decl->stmts->kids.empty())
-                                           ? decl->stmts->location
-                                           : decl->stmts->kids.back()->location;
-        const ast::DeclWithType* thisParam = decl->params.front();
-        decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
-            location, new ast::VariableExpr(location, thisParam)));
-    }
-    void genAttrStandardFuncs() {
-        ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
-            const = {&EnumAttrFuncGenerator::genCtorProto,
-                     &EnumAttrFuncGenerator::genCopyProto,
-                     &EnumAttrFuncGenerator::genDtorProto,
-                     &EnumAttrFuncGenerator::genAssignProto};
-        for (auto& generator : standardProtos) {
-            ast::FunctionDecl* decl = (this->*generator)();
-            produceForwardDecl(decl);
-            genFuncBody(decl);
-            if (CodeGen::isAssignment(decl->name)) {
-                appendReturnThis(decl);
-            }
-            produceDecl(decl);
-        }
-    }
-
-   private:
-    const CodeLocation& getLocation() const { return decl->location; }
-
-    ast::FunctionDecl* genProto(
-        std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
-        std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
-
-    void produceDecl(const ast::FunctionDecl* decl);
-    void produceForwardDecl(const ast::FunctionDecl* decl);
-
-    const ast::Decl* getDecl() const { return decl; }
-
-    ast::FunctionDecl* genPosnProto() const;
-    ast::FunctionDecl* genLabelProto() const;
-    ast::FunctionDecl* genValueProto() const;
-    ast::FunctionDecl* genSuccProto() const;
-    ast::FunctionDecl* genPredProto() const;
-
-    ast::FunctionDecl* genSuccPosProto() const;
-    ast::FunctionDecl* genPredPosProto() const;
-
-    // ---------------------------------------------------
-    // ast::FunctionDecl* genAttrCtorProto() const;
-    /// Changes the node inside a pointer so that it has the unused attribute.
-    void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
-        ast::DeclWithType* decl = declPtr.get_and_mutate();
-        decl->attributes.push_back(new ast::Attribute("unused"));
-    }
-
-    ast::ObjectDecl* dstParam() const {
-        return new ast::ObjectDecl(getLocation(), "_dst",
-                                   new ast::ReferenceType(new ast::EnumAttrType(
-                                       ast::deepCopy(instType))));
-    }
-
-    ast::ObjectDecl* srcParam() const {
-        return new ast::ObjectDecl(
-            getLocation(), "_src",
-            new ast::EnumAttrType(ast::deepCopy(instType)));
-    }
-
-    /// E = EnumAttrType<T>`
-    /// `void ?{}(E & _dst)`.
-    ast::FunctionDecl* genCtorProto() const {
-        return genProto("?{}", {dstParam()}, {});
-    }
-
-    /// void ?{}(E & _dst, E _src)`.
-    ast::FunctionDecl* genCopyProto() const {
-        return genProto("?{}", {dstParam(), srcParam()}, {});
-    }
-
-    ///`void ^?{}(E & _dst)`.
-    ast::FunctionDecl* genDtorProto() const {
-        // The destructor must be mutex on a concurrent type.
-        return genProto("^?{}", {dstParam()}, {});
-    }
-
-    /// `E ?{}(E & _dst, E _src)`.
-    ast::FunctionDecl* genAssignProto() const {
-        // Only the name is different, so just reuse the generation function.
-        auto retval = srcParam();
-        retval->name = "_ret";
-        return genProto("?=?", {dstParam(), srcParam()}, {retval});
-    }
-
-    void genFuncBody(ast::FunctionDecl* func) {
-        const CodeLocation& location = func->location;
-        auto& params = func->params;
-        if (InitTweak::isCopyConstructor(func) ||
-            InitTweak::isAssignment(func)) {
-            assert(2 == params.size());
-            auto dstParam = params.front().strict_as<ast::ObjectDecl>();
-            auto srcParam = params.back().strict_as<ast::ObjectDecl>();
-            func->stmts = genCopyBody(location, dstParam, srcParam);
-        } else {
-            assert(1 == params.size());
-            // Default constructor and destructor is empty.
-            func->stmts = new ast::CompoundStmt(location);
-            // Add unused attribute to parameter to silence warnings.
-            addUnusedAttribute(params.front());
-
-            // Just an extra step to make the forward and declaration match.
-            if (forwards.empty()) return;
-            ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
-                forwards.back().get_and_mutate());
-            addUnusedAttribute(fwd->params.front());
-        }
-    }
-
-    const ast::CompoundStmt* genCopyBody(const CodeLocation& location,
-                                         const ast::ObjectDecl* dstParam,
-                                         const ast::ObjectDecl* srcParam) {
-        return new ast::CompoundStmt(
-            location,
-            {new ast::ExprStmt(
-                location,
-                new ast::UntypedExpr(
-                    location, new ast::NameExpr(location, "__builtin_memcpy"),
-                    {
-                        new ast::AddressExpr(location, new ast::VariableExpr(
-                                                           location, dstParam)),
-                        new ast::AddressExpr(location, new ast::VariableExpr(
-                                                           location, srcParam)),
-                        new ast::SizeofExpr(location, srcParam->type),
-                    }))});
-    }
-
-    void genDtorBody(ast::FunctionDecl* func) {
-        const CodeLocation& location = func->location;
-        auto& params = func->params;
-        assert(1 == params.size());
-        func->stmts = new ast::CompoundStmt(location);
-        addUnusedAttribute(params.front());
-
-        // Just an extra step to make the forward and declaration match.
-        if (forwards.empty()) return;
-        ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
-            forwards.back().get_and_mutate());
-        addUnusedAttribute(fwd->params.front());
-    }
-
-    // ast::FunctionDecl*
-    // ----------------------------------------------------
-
-    ast::FunctionDecl* genSuccPredFunc(bool succ);
-
-    const ast::Init* getAutoInit(const ast::Init* prev) const;
-
-    std::vector<ast::ptr<ast::Init>> genLabelInit() const;
-
-    std::vector<ast::ptr<ast::Init>> genValueInit() const;
-    ast::ObjectDecl* genAttrArrayProto(
-        const ast::EnumAttribute attr, const CodeLocation& location,
-        std::vector<ast::ptr<ast::Init>>& inits) const;
-    void genValueOrLabelBody(ast::FunctionDecl* func,
-                             ast::ObjectDecl* arrDecl) const;
-    void genPosnBody(ast::FunctionDecl* func) const;
-    void genAttributesDecls(const ast::EnumAttribute attr);
+	const ast::EnumDecl* decl;
+	const ast::EnumInstType* instType;
+	unsigned int functionNesting;
+	ast::Linkage::Spec proto_linkage;
+
+public:
+	std::list<ast::ptr<ast::Decl>> forwards;
+	std::list<ast::ptr<ast::Decl>> definitions;
+
+	void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
+
+	EnumAttrFuncGenerator(
+			const ast::EnumDecl* decl,
+			const ast::EnumInstType* instType,
+			unsigned int functionNesting )
+		: decl(decl),
+		  instType{instType},
+		  functionNesting{functionNesting},
+		  proto_linkage{ast::Linkage::Cforall} {}
+
+	void genAttrFunctions();
+	void genSuccPredPosn();
+	void genSuccPredDecl();
+
+	void appendReturnThis(ast::FunctionDecl* decl) {
+		assert(1 <= decl->params.size());
+		assert(1 == decl->returns.size());
+		assert(decl->stmts);
+
+		const CodeLocation& location = (decl->stmts->kids.empty())
+		                                   ? decl->stmts->location
+		                                   : decl->stmts->kids.back()->location;
+		const ast::DeclWithType* thisParam = decl->params.front();
+		decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
+			location, new ast::VariableExpr(location, thisParam)));
+	}
+	void genAttrStandardFuncs() {
+		ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
+			const = {&EnumAttrFuncGenerator::genCtorProto,
+					 &EnumAttrFuncGenerator::genCopyProto,
+					 &EnumAttrFuncGenerator::genDtorProto,
+					 &EnumAttrFuncGenerator::genAssignProto};
+		for (auto& generator : standardProtos) {
+			ast::FunctionDecl* decl = (this->*generator)();
+			produceForwardDecl(decl);
+			genFuncBody(decl);
+			if (CodeGen::isAssignment(decl->name)) {
+				appendReturnThis(decl);
+			}
+			produceDecl(decl);
+		}
+	}
+
+private:
+	const CodeLocation& getLocation() const { return decl->location; }
+
+	ast::FunctionDecl* genProto(
+		std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
+		std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
+
+	void produceDecl(const ast::FunctionDecl* decl);
+	void produceForwardDecl(const ast::FunctionDecl* decl);
+
+	const ast::Decl* getDecl() const { return decl; }
+
+	ast::FunctionDecl* genPosnProto() const;
+	ast::FunctionDecl* genLabelProto() const;
+	ast::FunctionDecl* genValueProto() const;
+	ast::FunctionDecl* genSuccProto() const;
+	ast::FunctionDecl* genPredProto() const;
+
+	ast::FunctionDecl* genSuccPosProto() const;
+	ast::FunctionDecl* genPredPosProto() const;
+
+	// ---------------------------------------------------
+	// ast::FunctionDecl* genAttrCtorProto() const;
+	/// Changes the node inside a pointer so that it has the unused attribute.
+	void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
+		ast::DeclWithType* decl = declPtr.get_and_mutate();
+		decl->attributes.push_back(new ast::Attribute("unused"));
+	}
+
+	ast::ObjectDecl* dstParam() const {
+		return new ast::ObjectDecl(getLocation(), "_dst",
+		                           new ast::ReferenceType(new ast::EnumAttrType(
+		                               ast::deepCopy(instType))));
+	}
+
+	ast::ObjectDecl* srcParam() const {
+		return new ast::ObjectDecl(
+			getLocation(), "_src",
+			new ast::EnumAttrType(ast::deepCopy(instType)));
+	}
+
+	/// E = EnumAttrType<T>`
+	/// `void ?{}(E & _dst)`.
+	ast::FunctionDecl* genCtorProto() const {
+		return genProto("?{}", {dstParam()}, {});
+	}
+
+	/// void ?{}(E & _dst, E _src)`.
+	ast::FunctionDecl* genCopyProto() const {
+		return genProto("?{}", {dstParam(), srcParam()}, {});
+	}
+
+	///`void ^?{}(E & _dst)`.
+	ast::FunctionDecl* genDtorProto() const {
+		// The destructor must be mutex on a concurrent type.
+		return genProto("^?{}", {dstParam()}, {});
+	}
+
+	/// `E ?{}(E & _dst, E _src)`.
+	ast::FunctionDecl* genAssignProto() const {
+		// Only the name is different, so just reuse the generation function.
+		auto retval = srcParam();
+		retval->name = "_ret";
+		return genProto("?=?", {dstParam(), srcParam()}, {retval});
+	}
+
+	void genFuncBody(ast::FunctionDecl* func) {
+		const CodeLocation& location = func->location;
+		auto& params = func->params;
+		if (InitTweak::isCopyConstructor(func) ||
+			InitTweak::isAssignment(func)) {
+			assert(2 == params.size());
+			auto dstParam = params.front().strict_as<ast::ObjectDecl>();
+			auto srcParam = params.back().strict_as<ast::ObjectDecl>();
+			func->stmts = genCopyBody(location, dstParam, srcParam);
+		} else {
+			assert(1 == params.size());
+			// Default constructor and destructor is empty.
+			func->stmts = new ast::CompoundStmt(location);
+			// Add unused attribute to parameter to silence warnings.
+			addUnusedAttribute(params.front());
+
+			// Just an extra step to make the forward and declaration match.
+			if (forwards.empty()) return;
+			ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
+				forwards.back().get_and_mutate());
+			addUnusedAttribute(fwd->params.front());
+		}
+	}
+
+	const ast::CompoundStmt* genCopyBody( const CodeLocation& location,
+			const ast::ObjectDecl* dstParam, const ast::ObjectDecl* srcParam) {
+		return new ast::CompoundStmt(
+			location,
+			{new ast::ExprStmt(
+				location,
+				new ast::UntypedExpr(
+					location, new ast::NameExpr(location, "__builtin_memcpy"),
+					{
+						new ast::AddressExpr( location,
+							new ast::VariableExpr( location, dstParam ) ),
+						new ast::AddressExpr( location,
+							new ast::VariableExpr( location, srcParam ) ),
+						new ast::SizeofExpr( location, srcParam->type ),
+					}))});
+	}
+
+	void genDtorBody(ast::FunctionDecl* func) {
+		const CodeLocation& location = func->location;
+		auto& params = func->params;
+		assert(1 == params.size());
+		func->stmts = new ast::CompoundStmt(location);
+		addUnusedAttribute(params.front());
+
+		// Just an extra step to make the forward and declaration match.
+		if (forwards.empty()) return;
+		ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
+			forwards.back().get_and_mutate());
+		addUnusedAttribute(fwd->params.front());
+	}
+
+	// ast::FunctionDecl*
+	// ----------------------------------------------------
+
+	ast::FunctionDecl* genSuccPredFunc(bool succ);
+
+	const ast::Init* getAutoInit(const ast::Init* prev) const;
+
+	std::vector<ast::ptr<ast::Init>> genLabelInit() const;
+
+	std::vector<ast::ptr<ast::Init>> genValueInit() const;
+	ast::ObjectDecl* genAttrArrayProto(
+		const ast::EnumAttribute attr, const CodeLocation& location,
+		std::vector<ast::ptr<ast::Init>>& inits) const;
+	void genValueOrLabelBody(
+		ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
+	void genPosnBody(ast::FunctionDecl* func) const;
+	void genAttributesDecls(const ast::EnumAttribute attr);
 };
 
 std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
-    std::vector<ast::ptr<ast::Init>> inits;
-    for (size_t i = 0; i < decl->members.size(); i++) {
-        ast::ptr<ast::Decl> mem = decl->members.at(i);
-        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
-        assert(memAsObjectDecl);
-        inits.emplace_back(new ast::SingleInit(
-            mem->location,
-            ast::ConstantExpr::from_string(mem->location, mem->name)));
-    }
-    return inits;
+	std::vector<ast::ptr<ast::Init>> inits;
+	for (size_t i = 0; i < decl->members.size(); i++) {
+		ast::ptr<ast::Decl> mem = decl->members.at(i);
+		auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
+		assert(memAsObjectDecl);
+		inits.emplace_back(new ast::SingleInit(
+			mem->location,
+			ast::ConstantExpr::from_string(mem->location, mem->name)));
+	}
+	return inits;
 }
 
 std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
-    std::vector<ast::ptr<ast::Init>> inits;
-    for (size_t i = 0; i < decl->members.size(); i++) {
-        ast::ptr<ast::Decl> mem = decl->members.at(i);
-        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
-        assert(memAsObjectDecl);
-        if (memAsObjectDecl->init) {
-            inits.emplace_back(memAsObjectDecl->init);
-        } else {
-            const CodeLocation& location = mem->location;
-            if (i == 0) {
-                inits.emplace_back(new ast::SingleInit(
-                    location, ast::ConstantExpr::from_int(mem->location, 0)));
-            } else {
-                inits.emplace_back(getAutoInit(inits.at(i - 1)));
-            }
-        }
-    }
-    return inits;
+	std::vector<ast::ptr<ast::Init>> inits;
+	for (size_t i = 0; i < decl->members.size(); i++) {
+		ast::ptr<ast::Decl> mem = decl->members.at(i);
+		auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
+		assert(memAsObjectDecl);
+		if (memAsObjectDecl->init) {
+			inits.emplace_back(memAsObjectDecl->init);
+		} else {
+			const CodeLocation& location = mem->location;
+			if (i == 0) {
+				inits.emplace_back(new ast::SingleInit(
+					location, ast::ConstantExpr::from_int(mem->location, 0)));
+			} else {
+				inits.emplace_back(getAutoInit(inits.at(i - 1)));
+			}
+		}
+	}
+	return inits;
 }
 const ast::Init* EnumAttrFuncGenerator::getAutoInit(
-    const ast::Init* prev) const {
-    if (prev == nullptr) {
-        return new ast::SingleInit(
-            getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
-    }
-    auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
-    assert(prevInit);
-    auto prevInitExpr = prevInit->value;
-    if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
-        // Assume no string literal for now
-        return new ast::SingleInit(
-            getLocation(), ast::ConstantExpr::from_int(
-                               getLocation(), constInit->intValue() + 1));
-    } else {
-        auto untypedThisInit = new ast::UntypedExpr(
-            getLocation(), new ast::NameExpr(getLocation(), "?++"),
-            {prevInitExpr});
-        return new ast::SingleInit(getLocation(), untypedThisInit);
-    }
+	const ast::Init* prev) const {
+	if (prev == nullptr) {
+		return new ast::SingleInit(
+			getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
+	}
+	auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
+	assert(prevInit);
+	auto prevInitExpr = prevInit->value;
+	if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
+		// Assume no string literal for now
+		return new ast::SingleInit(
+			getLocation(), ast::ConstantExpr::from_int(
+				getLocation(), constInit->intValue() + 1));
+	} else {
+		auto untypedThisInit = new ast::UntypedExpr(
+			getLocation(), new ast::NameExpr(getLocation(), "?++"),
+			{prevInitExpr});
+		return new ast::SingleInit(getLocation(), untypedThisInit);
+	}
 }
 
 ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
-    std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
-    std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
-    ast::FunctionDecl* decl = new ast::FunctionDecl(
-        // Auto-generated routines use the type declaration's location.
-        getLocation(), std::move(name), {}, {}, std::move(params),
-        std::move(returns),
-        // Only a prototype, no body.
-        nullptr,
-        // Use static storage if we are at the top level.
-        (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
-        proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
-        // Auto-generated routines are inline to avoid conflicts.
-        ast::Function::Specs(ast::Function::Inline));
-    decl->fixUniqueId();
-    return decl;
+	std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
+	std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
+	ast::FunctionDecl* decl = new ast::FunctionDecl(
+		// Auto-generated routines use the type declaration's location.
+		getLocation(), std::move(name), {}, {}, std::move(params),
+		std::move(returns),
+		// Only a prototype, no body.
+		nullptr,
+		// Use static storage if we are at the top level.
+		(0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
+		proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
+		// Auto-generated routines are inline to avoid conflicts.
+		ast::Function::Specs(ast::Function::Inline));
+	decl->fixUniqueId();
+	return decl;
 }
 
 void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
-    assert(nullptr != decl->stmts);
-
-    definitions.push_back(decl);
+	assert(nullptr != decl->stmts);
+
+	definitions.push_back(decl);
 }
 
 void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
-    if (0 != functionNesting) return;
-    ast::FunctionDecl* fwd =
-        (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
-    fwd->fixUniqueId();
-    forwards.push_back(fwd);
+	if (0 != functionNesting) return;
+	ast::FunctionDecl* fwd =
+		(decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
+	fwd->fixUniqueId();
+	forwards.push_back(fwd);
 }
 
@@ -300,231 +297,233 @@
 
 ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
-    return genProto(
-        "labelE",
-        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
-        {new ast::ObjectDecl(
-            getLocation(), "_ret",
-            new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
+	return genProto(
+		"labelE",
+		{new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+		{new ast::ObjectDecl(
+			getLocation(), "_ret",
+			new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
 }
 
 ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
-    return genProto(
-        "valueE",
-        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
-        {new ast::ObjectDecl(getLocation(), "_ret",
-                             ast::deepCopy(decl->base))});
+	return genProto(
+		"valueE",
+		{new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+		{new ast::ObjectDecl(getLocation(), "_ret",
+		                     ast::deepCopy(decl->base))});
 }
 
 ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
-    return genProto(
-        "succ",
-        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
-        {new ast::ObjectDecl(getLocation(), "_ret",
-                             new ast::EnumInstType(decl))});
+	return genProto(
+		"succ",
+		{new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+		{new ast::ObjectDecl(getLocation(), "_ret",
+		                     new ast::EnumInstType(decl))});
 }
 
 ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
-    return genProto(
-        "pred",
-        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
-        {new ast::ObjectDecl(getLocation(), "_ret",
-                             new ast::EnumInstType(decl))});
+	return genProto(
+		"pred",
+		{new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+		{new ast::ObjectDecl(getLocation(), "_ret",
+		                     new ast::EnumInstType(decl))});
 }
 
 inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
-    return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
+	return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
 }
 
 ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
-    return genProto(
-        "_successor_",
-        {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
-        {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
-    );
+	return genProto(
+		"_successor_",
+		{new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
+		{new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
+	);
 }
 
 ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
-    return genProto(
-        "_predessor_",
-        {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
-        {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
-    );
+	return genProto(
+		"_predessor_",
+		{new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
+		{new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
+	);
 }
 
 ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
-    const ast::EnumAttribute attr, const CodeLocation& location,
-    std::vector<ast::ptr<ast::Init>>& inits) const {
-    ast::ArrayType* arrT = new ast::ArrayType(
-        attr == ast::EnumAttribute::Value
-            ? decl->base
-            : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
-        ast::ConstantExpr::from_int(decl->location, decl->members.size()),
-        ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
-
-    ast::ObjectDecl* objDecl =
-        new ast::ObjectDecl(decl->location, decl->getUnmangeldArrayName(attr),
-                            arrT, new ast::ListInit(location, std::move(inits)),
-                            ast::Storage::Static, ast::Linkage::AutoGen);
-
-    return objDecl;
+	const ast::EnumAttribute attr, const CodeLocation& location,
+	std::vector<ast::ptr<ast::Init>>& inits) const {
+	ast::ArrayType* arrT = new ast::ArrayType(
+		attr == ast::EnumAttribute::Value
+			? decl->base
+			: new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
+		ast::ConstantExpr::from_int(decl->location, decl->members.size()),
+		ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
+
+	ast::ObjectDecl* objDecl =
+		new ast::ObjectDecl(
+			decl->location, decl->getUnmangeldArrayName( attr ),
+			arrT, new ast::ListInit( location, std::move( inits ) ),
+			ast::Storage::Static, ast::Linkage::AutoGen );
+
+	return objDecl;
 }
 
 void EnumAttrFuncGenerator::genValueOrLabelBody(
-    ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
-    ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
-        func->location, "?[?]",
-        {new ast::NameExpr(func->location, arrDecl->name),
-         new ast::CastExpr(
-             func->location,
-             new ast::VariableExpr(func->location, func->params.front()),
-             new ast::EnumAttrType(new ast::EnumInstType(decl),
-                                   ast::EnumAttribute::Posn))});
-    func->stmts = new ast::CompoundStmt(
-        func->location, {new ast::ReturnStmt(func->location, untyped)});
+	ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
+	ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
+		func->location, "?[?]",
+		{new ast::NameExpr(func->location, arrDecl->name),
+			new ast::CastExpr(
+				func->location,
+				new ast::VariableExpr( func->location, func->params.front() ),
+				new ast::EnumAttrType( new ast::EnumInstType(decl),
+					ast::EnumAttribute::Posn))});
+	func->stmts = new ast::CompoundStmt(
+		func->location, {new ast::ReturnStmt(func->location, untyped)});
 }
 
 void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
-    auto castExpr = new ast::CastExpr(
-        func->location,
-        new ast::VariableExpr(func->location, func->params.front()),
-        new ast::EnumAttrType(new ast::EnumInstType(decl),
-                              ast::EnumAttribute::Posn));
-    func->stmts = new ast::CompoundStmt(
-        func->location, {new ast::ReturnStmt(func->location, castExpr)});
+	auto castExpr = new ast::CastExpr(
+		func->location,
+		new ast::VariableExpr(func->location, func->params.front()),
+		new ast::EnumAttrType(new ast::EnumInstType(decl),
+							  ast::EnumAttribute::Posn));
+	func->stmts = new ast::CompoundStmt(
+		func->location, {new ast::ReturnStmt(func->location, castExpr)});
 }
 
 void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
-    if (attr == ast::EnumAttribute::Value ||
-        attr == ast::EnumAttribute::Label) {
-        std::vector<ast::ptr<ast::Init>> inits =
-            attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
-        ast::ObjectDecl* arrayProto =
-            genAttrArrayProto(attr, getLocation(), inits);
-        forwards.push_back(arrayProto);
-
-        ast::FunctionDecl* funcProto = attr == ast::EnumAttribute::Value
-                                           ? genValueProto()
-                                           : genLabelProto();
-        produceForwardDecl(funcProto);
-        genValueOrLabelBody(funcProto, arrayProto);
-        produceDecl(funcProto);
-    } else {
-        ast::FunctionDecl* funcProto = genPosnProto();
-        produceForwardDecl(funcProto);
-        genPosnBody(funcProto);
-        produceDecl(funcProto);
-    }
+	if (attr == ast::EnumAttribute::Value ||
+		attr == ast::EnumAttribute::Label) {
+		std::vector<ast::ptr<ast::Init>> inits =
+			attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
+		ast::ObjectDecl* arrayProto =
+			genAttrArrayProto(attr, getLocation(), inits);
+		forwards.push_back(arrayProto);
+
+		ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
+		                               ? genValueProto()
+		                               : genLabelProto();
+		produceForwardDecl(funcProto);
+		genValueOrLabelBody(funcProto, arrayProto);
+		produceDecl(funcProto);
+	} else {
+		ast::FunctionDecl* funcProto = genPosnProto();
+		produceForwardDecl(funcProto);
+		genPosnBody(funcProto);
+		produceDecl(funcProto);
+	}
 }
 
 ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
-    ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
-    produceForwardDecl(funcDecl);
-
-    const CodeLocation& location = getLocation();
-
-    auto& params = funcDecl->params;
-    assert(params.size() == 1);
-    auto param = params.front().strict_as<ast::ObjectDecl>();
-
-
-    auto rets = funcDecl->returns;
-    assert(params.size() == 1);
-    auto ret = rets.front().strict_as<ast::ObjectDecl>();
-    auto retType = ret->type.strict_as<ast::EnumAttrType>();
-
-    auto addOneExpr = ast::UntypedExpr::createCall( location,
-        succ? "?+?": "?-?",
-        {new ast::VariableExpr(location, param),
-        ast::ConstantExpr::from_int(location, 1)}
-    );
-
-    funcDecl->stmts = new ast::CompoundStmt(
-        location, {
-            new ast::ReturnStmt(
-                location, 
-                new ast::CastExpr(location, addOneExpr, retType) 
-            )
-        }
-    );
-
-    return funcDecl;
+	ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
+	produceForwardDecl(funcDecl);
+
+	const CodeLocation& location = getLocation();
+
+	auto& params = funcDecl->params;
+	assert(params.size() == 1);
+	auto param = params.front().strict_as<ast::ObjectDecl>();
+
+
+	auto rets = funcDecl->returns;
+	assert(params.size() == 1);
+	auto ret = rets.front().strict_as<ast::ObjectDecl>();
+	auto retType = ret->type.strict_as<ast::EnumAttrType>();
+
+	auto addOneExpr = ast::UntypedExpr::createCall( location,
+		succ? "?+?": "?-?",
+		{new ast::VariableExpr(location, param),
+		ast::ConstantExpr::from_int(location, 1)}
+	);
+
+	funcDecl->stmts = new ast::CompoundStmt(
+		location, {
+			new ast::ReturnStmt(
+				location,
+				new ast::CastExpr(location, addOneExpr, retType)
+			)
+		}
+	);
+
+	return funcDecl;
 }
 
 void EnumAttrFuncGenerator::genAttrFunctions() {
-    if (decl->base) {
-        genAttributesDecls(ast::EnumAttribute::Value);
-        genAttributesDecls(ast::EnumAttribute::Label);
-        genAttributesDecls(ast::EnumAttribute::Posn);
-    }
+	if (decl->base) {
+		genAttributesDecls(ast::EnumAttribute::Value);
+		genAttributesDecls(ast::EnumAttribute::Label);
+		genAttributesDecls(ast::EnumAttribute::Posn);
+	}
 }
 
 void EnumAttrFuncGenerator::genSuccPredDecl() {
-    if (decl->base) {
-        auto succProto = genSuccProto();
-        auto predProto = genPredProto();
-
-        produceForwardDecl(succProto);
-        produceForwardDecl(predProto);
-    }
+	if (decl->base) {
+		auto succProto = genSuccProto();
+		auto predProto = genPredProto();
+
+		produceForwardDecl(succProto);
+		produceForwardDecl(predProto);
+	}
 }
 
 void EnumAttrFuncGenerator::genSuccPredPosn() {
-    if (decl->base) {
-        ast::FunctionDecl* succ = genSuccPredFunc(true);
-        ast::FunctionDecl* pred = genSuccPredFunc(false);
-
-        produceDecl(succ);
-        produceDecl(pred);
-    }
+	if (decl->base) {
+		ast::FunctionDecl* succ = genSuccPredFunc(true);
+		ast::FunctionDecl* pred = genSuccPredFunc(false);
+
+		produceDecl(succ);
+		produceDecl(pred);
+	}
 }
 
 void EnumAttrFuncGenerator::generateAndAppendFunctions(
-    std::list<ast::ptr<ast::Decl>>& decls) {
-    // Generate the functions (they go into forwards and definitions).
-    genAttrStandardFuncs();
-    genAttrFunctions();
-    genSuccPredDecl();
-    genSuccPredPosn(); // Posn
-    // Now export the lists contents.
-    decls.splice(decls.end(), forwards);
-    decls.splice(decls.end(), definitions);
+	std::list<ast::ptr<ast::Decl>>& decls) {
+	// Generate the functions (they go into forwards and definitions).
+	genAttrStandardFuncs();
+	genAttrFunctions();
+	genSuccPredDecl();
+	genSuccPredPosn(); // Posn
+	// Now export the lists contents.
+	decls.splice(decls.end(), forwards);
+	decls.splice(decls.end(), definitions);
 }
 
 // ---------------------------------------------------------
 
-struct ImplementEnumFunc final : public ast::WithDeclsToAdd<>,
-                                 public ast::WithShortCircuiting {
-    void previsit(const ast::EnumDecl* enumDecl);
-    void previsit(const ast::FunctionDecl* functionDecl);
-    void postvisit(const ast::FunctionDecl* functionDecl);
-
-   private:
-    // Current level of nested functions.
-    unsigned int functionNesting = 0;
+struct ImplementEnumFunc final :
+		public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
+	void previsit(const ast::EnumDecl* enumDecl);
+	void previsit(const ast::FunctionDecl* functionDecl);
+	void postvisit(const ast::FunctionDecl* functionDecl);
+
+private:
+	// Current level of nested functions.
+	unsigned int functionNesting = 0;
 };
 
 void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
-    if (!enumDecl->body) return;
-    if (!enumDecl->base) return;
-
-    ast::EnumInstType enumInst(enumDecl->name);
-    enumInst.base = enumDecl;
-
-    EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
-    gen.generateAndAppendFunctions(declsToAddAfter);
+	if (!enumDecl->body) return;
+	if (!enumDecl->base) return;
+
+	ast::EnumInstType enumInst(enumDecl->name);
+	enumInst.base = enumDecl;
+
+	EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
+	gen.generateAndAppendFunctions(declsToAddAfter);
 }
 
 void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
-    functionNesting += 1;
+	functionNesting += 1;
 }
 
 void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
-    functionNesting -= 1;
-}
-
-}  // namespace
+	functionNesting -= 1;
+}
+
+} // namespace
 
 void implementEnumFunc(ast::TranslationUnit& translationUnit) {
-    ast::Pass<ImplementEnumFunc>::run(translationUnit);
-}
-}  // namespace Validate
+	ast::Pass<ImplementEnumFunc>::run(translationUnit);
+}
+
+} // namespace Validate
Index: src/Virtual/VirtualDtor.cpp
===================================================================
--- src/Virtual/VirtualDtor.cpp	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ src/Virtual/VirtualDtor.cpp	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -28,320 +28,320 @@
 
 struct CtorDtor {
-    FunctionDecl * dtorSetup;  // dtor init routine to add after last dtor for a struct
-    FunctionDecl * deleteFn;
-    FunctionDecl * lastDtor;    // pointer to last occurence of dtor to know where to insert after
-
-    CtorDtor() : dtorSetup(nullptr), deleteFn(nullptr), lastDtor(nullptr) {}
+	FunctionDecl * dtorSetup;  // dtor init routine to add after last dtor for a struct
+	FunctionDecl * deleteFn;
+	FunctionDecl * lastDtor;    // pointer to last occurence of dtor to know where to insert after
+
+	CtorDtor() : dtorSetup(nullptr), deleteFn(nullptr), lastDtor(nullptr) {}
 };
 
 class CtorDtorTable {
-    unordered_map<const StructDecl *, CtorDtor> & structMap;
+	unordered_map<const StructDecl *, CtorDtor> & structMap;
+
+public:
+	// if dtor is last dtor for this decl return the routine to add afterwards
+	// otherwise return nullptr
+	FunctionDecl * getToAddLater( const StructDecl * decl, FunctionDecl * dtor, FunctionDecl ** retDeleteFn ) {
+		auto iter = structMap.find( decl );
+		if ( iter == structMap.end() || iter->second.lastDtor != dtor ) return nullptr; // check if this is needed
+		*retDeleteFn = iter->second.deleteFn;
+		return iter->second.dtorSetup;
+	}
+
+	// return if the dtorSetup field has been defined for this decl
+	bool inTable( const StructDecl * decl ) {
+		auto iter = structMap.find( decl );
+		return iter->second.dtorSetup != nullptr;
+	}
+
+	void addLater( const StructDecl * decl, FunctionDecl * dtorSetup, FunctionDecl * deleteFn ) {
+		auto iter = structMap.find( decl );
+		iter->second.dtorSetup = dtorSetup;
+		iter->second.deleteFn = deleteFn;
+	}
+
+	void addDtor( const StructDecl * decl, FunctionDecl * dtor ) {
+		auto iter = structMap.find( decl );
+		iter->second.lastDtor = dtor;
+	}
+
+	CtorDtorTable( unordered_map<const StructDecl *, CtorDtor> & structMap ) : structMap(structMap) {}
+};
+
+struct CollectStructDecls : public ast::WithGuards {
+	unordered_map<const StructDecl *, CtorDtor> & structDecls;
+	StructDecl * parentDecl;
+	bool insideStruct = false;
+	bool namedDecl = false;
+
+	const StructDecl ** virtualDtor;
+
+	// finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
+	void previsit( const StructDecl * decl ) {
+		if ( !decl->body ) return;
+		if( decl->name == "virtual_dtor" ) {
+			structDecls.emplace( make_pair( decl, CtorDtor() ) );
+			*virtualDtor = decl;
+		} else {
+			GuardValue(insideStruct);
+			insideStruct = true;
+			parentDecl = mutate( decl );
+		}
+	}
+
+	// this catches structs of the form:
+	//     struct derived_type { virtual_dtor a; };
+	// since they should be:
+	//     struct derived_type { inline virtual_dtor; };
+	void previsit ( const ObjectDecl * decl ) {
+		if ( insideStruct && ! decl->name.empty() ) {
+			GuardValue(namedDecl);
+			namedDecl = true;
+		}
+	}
+
+	// this collects the derived actor and message struct decl ptrs
+	void postvisit( const StructInstType * node ) {
+		if ( ! *virtualDtor ) return;
+		if ( insideStruct && !namedDecl ) {
+			auto structIter = structDecls.find( node->aggr() );
+			if ( structIter != structDecls.end() )
+				structDecls.emplace( make_pair( parentDecl, CtorDtor() ) );
+		}
+	}
 
   public:
-    // if dtor is last dtor for this decl return the routine to add afterwards
-    // otherwise return nullptr
-    FunctionDecl * getToAddLater( const StructDecl * decl, FunctionDecl * dtor, FunctionDecl ** retDeleteFn ) {
-        auto iter = structMap.find( decl );
-        if ( iter == structMap.end() || iter->second.lastDtor != dtor ) return nullptr; // check if this is needed
-        *retDeleteFn = iter->second.deleteFn;
-        return iter->second.dtorSetup;
-    }
-
-    // return if the dtorSetup field has been defined for this decl
-    bool inTable( const StructDecl * decl ) {
-        auto iter = structMap.find( decl );
-        return iter->second.dtorSetup != nullptr;
-    }
-
-    void addLater( const StructDecl * decl, FunctionDecl * dtorSetup, FunctionDecl * deleteFn ) {
-        auto iter = structMap.find( decl );
-        iter->second.dtorSetup = dtorSetup;
-        iter->second.deleteFn = deleteFn;
-    }
-
-    void addDtor( const StructDecl * decl, FunctionDecl * dtor ) {
-        auto iter = structMap.find( decl );
-        iter->second.lastDtor = dtor;
-    }
-
-    CtorDtorTable( unordered_map<const StructDecl *, CtorDtor> & structMap ) : structMap(structMap) {}
-};
-
-struct CollectStructDecls : public ast::WithGuards {
-    unordered_map<const StructDecl *, CtorDtor> & structDecls;
-    StructDecl * parentDecl;
-    bool insideStruct = false;
-    bool namedDecl = false;
-
-    const StructDecl ** virtualDtor;
-
-    // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
-    void previsit( const StructDecl * decl ) {
-        if ( !decl->body ) return;
-        if( decl->name == "virtual_dtor" ) {
-            structDecls.emplace( make_pair( decl, CtorDtor() ) );
-            *virtualDtor = decl;
-        } else {
-            GuardValue(insideStruct);
-            insideStruct = true;
-            parentDecl = mutate( decl );
-        }
-	}
-
-    // this catches structs of the form:
-    //     struct derived_type { virtual_dtor a; };
-    // since they should be:
-    //     struct derived_type { inline virtual_dtor; };
-    void previsit ( const ObjectDecl * decl ) {
-        if ( insideStruct && ! decl->name.empty() ) {
-            GuardValue(namedDecl);
-            namedDecl = true;
-        }
-    }
-
-    // this collects the derived actor and message struct decl ptrs
-    void postvisit( const StructInstType * node ) {
-        if ( ! *virtualDtor ) return;
-        if ( insideStruct && !namedDecl ) {
-            auto structIter = structDecls.find( node->aggr() );    
-            if ( structIter != structDecls.end() )
-                structDecls.emplace( make_pair( parentDecl, CtorDtor() ) );
-        }
-	}
-
-  public:
-    CollectStructDecls( unordered_map<const StructDecl *, CtorDtor> & structDecls, const StructDecl ** virtualDtor ):
-        structDecls( structDecls ), virtualDtor(virtualDtor) {}
+	CollectStructDecls( unordered_map<const StructDecl *, CtorDtor> & structDecls, const StructDecl ** virtualDtor ):
+		structDecls( structDecls ), virtualDtor(virtualDtor) {}
 };
 
 // generates the forward decl of virtual dtor setting routine and delete routine
 // generates the call to the virtual dtor routine in each appropriate ctor
-// collects data needed for next pass that does the circular defn resolution 
+// collects data needed for next pass that does the circular defn resolution
 //     for dtor setters and delete fns (via table above)
 struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> {
-    unordered_map<const StructDecl *, CtorDtor> & structDecls;
-    CtorDtorTable & torDecls;
-    const StructDecl ** virtualDtor;
-
-    // collects the dtor info for actors/messages
-    // gens the dtor fwd decl and dtor call in ctor
-    void previsit( const FunctionDecl * decl ) {
-        if ( (decl->name != "?{}" && decl->name != "^?{}") || decl->params.size() == 0 
-            || !decl->stmts || (decl->name == "^?{}" && decl->params.size() != 1)) return;
-
-        // the first param should be a reference
-        const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
-        if ( !ref ) return;
-
-        // the reference should be to a struct instance
-        const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
-        if ( !instType ) return;
-
-        // return if not ctor/dtor for an actor or message
-        auto structIter = structDecls.find( instType->aggr() );
-        if ( structIter == structDecls.end() ) return;
-
-        // If first param not named we need to name it to use it
-        if ( decl->params.at(0)->name == "" )
-            mutate( decl->params.at(0).get() )->name = "__CFA_Virt_Dtor_param";
-
-        if ( decl->name == "^?{}") {
-            torDecls.addDtor( structIter->first, mutate( decl ) );
-
-            CompoundStmt * dtorBody = mutate( decl->stmts.get() );
-            // Adds the following to the start of any actor/message dtor:
-            //  __CFA_dtor_shutdown( this );
-            dtorBody->push_front( 
-                new IfStmt( decl->location,
-                    new UntypedExpr (
-                        decl->location,
-                        new NameExpr( decl->location, "__CFA_dtor_shutdown" ),
-                        {
-                            new NameExpr( decl->location, decl->params.at(0)->name )
-                        }
-                    ),
-                    new ReturnStmt( decl->location, nullptr )
-                )
-            );
-            return;
-        }
-
-        // not dtor by this point so must be ctor
-        CompoundStmt * ctorBody = mutate( decl->stmts.get() );
-        // Adds the following to the end of any actor/message ctor:
-        //  __CFA_set_dtor( this );
-        ctorBody->push_back( new ExprStmt(
-            decl->location,
-            new UntypedExpr (
-                decl->location,
-                new NameExpr( decl->location, "__CFA_set_dtor" ),
-                {
-                    new NameExpr( decl->location, decl->params.at(0)->name )
-                }
-            )
-        ));
-        
-        if ( torDecls.inTable( structIter->first ) ) return;
-
-        // Generates the following:
-        // void __CFA_set_dtor( Derived_type & this ){
-        //     void (*__my_dtor)( Derived_type & ) = ^?{};
-        //     this.__virtual_dtor = (void (*)( Base_type & ))__my_dtor;
-        //     this.__virtual_obj_start = (void *)(&this);
-        // }
-        CompoundStmt * setDtorBody = new CompoundStmt( decl->location );
-
-        // Function type is: (void (*)(Derived_type &))
-        FunctionType * derivedDtor = new FunctionType();
-        derivedDtor->params.push_back( ast::deepCopy( ref ) );
-
-        // Generates:
-        //      void (*__my_dtor)( Derived_type & ) = ^?{};
-        setDtorBody->push_back( new DeclStmt(
-            decl->location,
-            new ObjectDecl(
-                decl->location,
-                "__my_dtor",
-                new PointerType( derivedDtor ),
-                new SingleInit( decl->location, new NameExpr( decl->location, "^?{}" ) )
-            )
-        ));
-
-        // Function type is: (void (*)( Base_type & ))
-        FunctionType * baseDtor = new FunctionType();
-        baseDtor->params.push_back( new ReferenceType( new StructInstType( *virtualDtor ) ) );
-
-        // Generates:
-        //     __CFA_set_virt_dtor( this, (void (*)( Base_type & ))__my_dtor )
-        setDtorBody->push_back( new ExprStmt(
-            decl->location,
-            new UntypedExpr (
-                decl->location,
-                new NameExpr( decl->location, "__CFA_set_virt_dtor" ),
-                {
-                    new NameExpr( decl->location, "this" ),
-                    new CastExpr( decl->location, new NameExpr( decl->location, "__my_dtor" ), new PointerType( baseDtor ), ExplicitCast )
-                }
-            )
-        ));
-
-        // Generates:
-        //     __CFA_set_virt_start( (void *)(&this) );
-        setDtorBody->push_back( new ExprStmt(
-            decl->location,
-            new UntypedExpr (
-                decl->location, 
-                new NameExpr( decl->location, "__CFA_set_virt_start" ),
-                {
-                    new NameExpr( decl->location, "this" ),
-                    new CastExpr(
-                        decl->location, 
-                        new AddressExpr( decl->location, new NameExpr( decl->location, "this" )), 
-                        new PointerType( new ast::VoidType() ), ExplicitCast
-                        )
-                }
-            )
-        ));
-
-        // put it all together into the complete function decl from above
-        FunctionDecl * setDtorFunction = new FunctionDecl(
-            decl->location,
-            "__CFA_set_dtor",
-            {
-                new ObjectDecl(
-                    decl->location,
-                    "this",
-                    ast::deepCopy( ref )
-                ),
-            },                      // params
-            {},
-            nullptr,               // body
-            { Storage::Static },    // storage
-            Linkage::Cforall,       // linkage
-            {},                     // attributes
-            { Function::Inline }
-        );
-
-        declsToAddBefore.push_back( ast::deepCopy( setDtorFunction ) );
-
-        setDtorFunction->stmts = setDtorBody;
-
-        // The following generates the following specialized delete routine:
-        // static inline void delete( derived_type * ptr ) {
-        //     if ( ptr )
-        //         ^(*ptr){};
-        //     __CFA_virt_free( *ptr );
-        // }
-        CompoundStmt * deleteFnBody = new CompoundStmt( decl->location );
-
-        // Generates:
-        //     if ( ptr )
-        //         ^(*ptr){};
-        deleteFnBody->push_back(
-            new IfStmt(
-                decl->location,
-                UntypedExpr::createCall(
-                    decl->location,
-                    "?!=?",
-                    {
-                        new NameExpr( decl->location, "ptr" ),
-                        ConstantExpr::null( decl->location, new PointerType( ast::deepCopy( instType ) ) )
-                    }
-                ),
-                new ExprStmt(
-                    decl->location,
-                    UntypedExpr::createCall( 
-                        decl->location, 
-                        "^?{}",
-                        {
-                            UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
-                        }
-                    )
-                )
-            )
-        );
-
-        // Generates:
-        //     __CFA_virt_free( *ptr );
-        deleteFnBody->push_back( new ExprStmt(
-                decl->location,
-                UntypedExpr::createCall( 
-                    decl->location, 
-                    "__CFA_virt_free",
-                    {
-                        UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
-                    }
-                )
-            )
-        );
-
-        FunctionDecl * deleteFn = new FunctionDecl(
-            decl->location,
-            "delete",
-            {
-                new ObjectDecl(
-                    decl->location,
-                    "ptr",
-                    new PointerType( ast::deepCopy( instType ) )
-                ),
-            },                      // params
-            {},
-            nullptr,               // body
-            { Storage::Static },    // storage
-            Linkage::Cforall,       // linkage
-            {},                     // attributes
-            { Function::Inline }
-        );
-
-        declsToAddBefore.push_back( ast::deepCopy( deleteFn ) );
-
-        deleteFn->stmts = deleteFnBody;
-
-        torDecls.addLater( structIter->first, setDtorFunction, deleteFn );
-    }
+	unordered_map<const StructDecl *, CtorDtor> & structDecls;
+	CtorDtorTable & torDecls;
+	const StructDecl ** virtualDtor;
+
+	// collects the dtor info for actors/messages
+	// gens the dtor fwd decl and dtor call in ctor
+	void previsit( const FunctionDecl * decl ) {
+		if ( (decl->name != "?{}" && decl->name != "^?{}") || decl->params.size() == 0
+			|| !decl->stmts || (decl->name == "^?{}" && decl->params.size() != 1)) return;
+
+		// the first param should be a reference
+		const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
+		if ( !ref ) return;
+
+		// the reference should be to a struct instance
+		const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
+		if ( !instType ) return;
+
+		// return if not ctor/dtor for an actor or message
+		auto structIter = structDecls.find( instType->aggr() );
+		if ( structIter == structDecls.end() ) return;
+
+		// If first param not named we need to name it to use it
+		if ( decl->params.at(0)->name == "" )
+			mutate( decl->params.at(0).get() )->name = "__CFA_Virt_Dtor_param";
+
+		if ( decl->name == "^?{}") {
+			torDecls.addDtor( structIter->first, mutate( decl ) );
+
+			CompoundStmt * dtorBody = mutate( decl->stmts.get() );
+			// Adds the following to the start of any actor/message dtor:
+			//  __CFA_dtor_shutdown( this );
+			dtorBody->push_front(
+				new IfStmt( decl->location,
+					new UntypedExpr (
+						decl->location,
+						new NameExpr( decl->location, "__CFA_dtor_shutdown" ),
+						{
+							new NameExpr( decl->location, decl->params.at(0)->name )
+						}
+					),
+					new ReturnStmt( decl->location, nullptr )
+				)
+			);
+			return;
+		}
+
+		// not dtor by this point so must be ctor
+		CompoundStmt * ctorBody = mutate( decl->stmts.get() );
+		// Adds the following to the end of any actor/message ctor:
+		//  __CFA_set_dtor( this );
+		ctorBody->push_back( new ExprStmt(
+			decl->location,
+			new UntypedExpr (
+				decl->location,
+				new NameExpr( decl->location, "__CFA_set_dtor" ),
+				{
+					new NameExpr( decl->location, decl->params.at(0)->name )
+				}
+			)
+		));
+
+		if ( torDecls.inTable( structIter->first ) ) return;
+
+		// Generates the following:
+		// void __CFA_set_dtor( Derived_type & this ){
+		//     void (*__my_dtor)( Derived_type & ) = ^?{};
+		//     this.__virtual_dtor = (void (*)( Base_type & ))__my_dtor;
+		//     this.__virtual_obj_start = (void *)(&this);
+		// }
+		CompoundStmt * setDtorBody = new CompoundStmt( decl->location );
+
+		// Function type is: (void (*)(Derived_type &))
+		FunctionType * derivedDtor = new FunctionType();
+		derivedDtor->params.push_back( ast::deepCopy( ref ) );
+
+		// Generates:
+		//      void (*__my_dtor)( Derived_type & ) = ^?{};
+		setDtorBody->push_back( new DeclStmt(
+			decl->location,
+			new ObjectDecl(
+				decl->location,
+				"__my_dtor",
+				new PointerType( derivedDtor ),
+				new SingleInit( decl->location, new NameExpr( decl->location, "^?{}" ) )
+			)
+		));
+
+		// Function type is: (void (*)( Base_type & ))
+		FunctionType * baseDtor = new FunctionType();
+		baseDtor->params.push_back( new ReferenceType( new StructInstType( *virtualDtor ) ) );
+
+		// Generates:
+		//     __CFA_set_virt_dtor( this, (void (*)( Base_type & ))__my_dtor )
+		setDtorBody->push_back( new ExprStmt(
+			decl->location,
+			new UntypedExpr (
+				decl->location,
+				new NameExpr( decl->location, "__CFA_set_virt_dtor" ),
+				{
+					new NameExpr( decl->location, "this" ),
+					new CastExpr( decl->location, new NameExpr( decl->location, "__my_dtor" ), new PointerType( baseDtor ), ExplicitCast )
+				}
+			)
+		));
+
+		// Generates:
+		//     __CFA_set_virt_start( (void *)(&this) );
+		setDtorBody->push_back( new ExprStmt(
+			decl->location,
+			new UntypedExpr (
+				decl->location,
+				new NameExpr( decl->location, "__CFA_set_virt_start" ),
+				{
+					new NameExpr( decl->location, "this" ),
+					new CastExpr(
+						decl->location,
+						new AddressExpr( decl->location, new NameExpr( decl->location, "this" )),
+						new PointerType( new ast::VoidType() ), ExplicitCast
+						)
+				}
+			)
+		));
+
+		// put it all together into the complete function decl from above
+		FunctionDecl * setDtorFunction = new FunctionDecl(
+			decl->location,
+			"__CFA_set_dtor",
+			{
+				new ObjectDecl(
+					decl->location,
+					"this",
+					ast::deepCopy( ref )
+				),
+			},                      // params
+			{},
+			nullptr,               // body
+			{ Storage::Static },    // storage
+			Linkage::Cforall,       // linkage
+			{},                     // attributes
+			{ Function::Inline }
+		);
+
+		declsToAddBefore.push_back( ast::deepCopy( setDtorFunction ) );
+
+		setDtorFunction->stmts = setDtorBody;
+
+		// The following generates the following specialized delete routine:
+		// static inline void delete( derived_type * ptr ) {
+		//     if ( ptr )
+		//         ^(*ptr){};
+		//     __CFA_virt_free( *ptr );
+		// }
+		CompoundStmt * deleteFnBody = new CompoundStmt( decl->location );
+
+		// Generates:
+		//     if ( ptr )
+		//         ^(*ptr){};
+		deleteFnBody->push_back(
+			new IfStmt(
+				decl->location,
+				UntypedExpr::createCall(
+					decl->location,
+					"?!=?",
+					{
+						new NameExpr( decl->location, "ptr" ),
+						ConstantExpr::null( decl->location, new PointerType( ast::deepCopy( instType ) ) )
+					}
+				),
+				new ExprStmt(
+					decl->location,
+					UntypedExpr::createCall(
+						decl->location,
+						"^?{}",
+						{
+							UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
+						}
+					)
+				)
+			)
+		);
+
+		// Generates:
+		//     __CFA_virt_free( *ptr );
+		deleteFnBody->push_back( new ExprStmt(
+				decl->location,
+				UntypedExpr::createCall(
+					decl->location,
+					"__CFA_virt_free",
+					{
+						UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
+					}
+				)
+			)
+		);
+
+		FunctionDecl * deleteFn = new FunctionDecl(
+			decl->location,
+			"delete",
+			{
+				new ObjectDecl(
+					decl->location,
+					"ptr",
+					new PointerType( ast::deepCopy( instType ) )
+				),
+			},                      // params
+			{},
+			nullptr,               // body
+			{ Storage::Static },    // storage
+			Linkage::Cforall,       // linkage
+			{},                     // attributes
+			{ Function::Inline }
+		);
+
+		declsToAddBefore.push_back( ast::deepCopy( deleteFn ) );
+
+		deleteFn->stmts = deleteFnBody;
+
+		torDecls.addLater( structIter->first, setDtorFunction, deleteFn );
+	}
 
   public:
-    GenFuncsCreateTables( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls, const StructDecl ** virtualDtor ):
-    structDecls(structDecls), torDecls(torDecls), virtualDtor(virtualDtor) {}
+	GenFuncsCreateTables( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls, const StructDecl ** virtualDtor ):
+	structDecls(structDecls), torDecls(torDecls), virtualDtor(virtualDtor) {}
 };
 
@@ -349,55 +349,54 @@
 // generates the trailing definitions of dtor setting routines for virtual dtors on messages and actors
 // generates the function defns of __CFA_set_dtor
-// separate pass is needed since  __CFA_set_dtor needs to be defined after 
+// separate pass is needed since  __CFA_set_dtor needs to be defined after
 //   the last dtor defn which is found in prior pass
 struct GenSetDtor : public ast::WithDeclsToAdd<> {
-    unordered_map<const StructDecl *, CtorDtor> & structDecls; // set of decls that inherit from virt dtor
-    CtorDtorTable & torDecls;
-
-    // handles adding the declaration of the dtor init routine after the last dtor detected
-    void postvisit( const FunctionDecl * decl ) {
-        if ( decl->name != "^?{}" || !decl->stmts || decl->params.size() != 1 ) return;
-
-        // the one param should be a reference
-        const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
-        if ( !ref ) return;
-
-        // the reference should be to a struct instance
-        const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
-        if ( !instType ) return;
-
-        FunctionDecl * deleteRtn;
-
-        // returns nullptr if not in table
-        FunctionDecl * maybeAdd = torDecls.getToAddLater( instType->aggr(), mutate( decl ), &deleteRtn );
-        if ( maybeAdd ) {
-            declsToAddAfter.push_back( maybeAdd );
-            declsToAddAfter.push_back( deleteRtn );
-        }
-    }
-
-  public:
-    GenSetDtor( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls ):
-        structDecls(structDecls), torDecls(torDecls) {}
+	unordered_map<const StructDecl *, CtorDtor> & structDecls; // set of decls that inherit from virt dtor
+	CtorDtorTable & torDecls;
+
+	// handles adding the declaration of the dtor init routine after the last dtor detected
+	void postvisit( const FunctionDecl * decl ) {
+		if ( decl->name != "^?{}" || !decl->stmts || decl->params.size() != 1 ) return;
+
+		// the one param should be a reference
+		const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
+		if ( !ref ) return;
+
+		// the reference should be to a struct instance
+		const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
+		if ( !instType ) return;
+
+		FunctionDecl * deleteRtn;
+
+		// returns nullptr if not in table
+		FunctionDecl * maybeAdd = torDecls.getToAddLater( instType->aggr(), mutate( decl ), &deleteRtn );
+		if ( maybeAdd ) {
+			declsToAddAfter.push_back( maybeAdd );
+			declsToAddAfter.push_back( deleteRtn );
+		}
+	}
+
+public:
+	GenSetDtor( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls ):
+		structDecls(structDecls), torDecls(torDecls) {}
 };
 
 void implementVirtDtors( TranslationUnit & translationUnit ) {
-    // unordered_map to collect all derived types and associated data
-    unordered_map<const StructDecl *, CtorDtor> structDecls;
-    CtorDtorTable torDecls( structDecls );
-
-    const StructDecl * virtualDtorPtr = nullptr;
-    const StructDecl ** virtualDtor = &virtualDtorPtr;
-
-    // first pass collects all structs that inherit from virtual_dtor
-    Pass<CollectStructDecls>::run( translationUnit, structDecls, virtualDtor );
-
-    // second pass locates all dtor/ctor routines that need modifying or need fns inserted before/after
-    Pass<GenFuncsCreateTables>::run( translationUnit, structDecls, torDecls, virtualDtor );
-
-    // The third pass adds the forward decls needed to resolve circular defn problems
-    Pass<GenSetDtor>::run( translationUnit, structDecls, torDecls );
+	// unordered_map to collect all derived types and associated data
+	unordered_map<const StructDecl *, CtorDtor> structDecls;
+	CtorDtorTable torDecls( structDecls );
+
+	const StructDecl * virtualDtorPtr = nullptr;
+	const StructDecl ** virtualDtor = &virtualDtorPtr;
+
+	// first pass collects all structs that inherit from virtual_dtor
+	Pass<CollectStructDecls>::run( translationUnit, structDecls, virtualDtor );
+
+	// second pass locates all dtor/ctor routines that need modifying or need fns inserted before/after
+	Pass<GenFuncsCreateTables>::run( translationUnit, structDecls, torDecls, virtualDtor );
+
+	// The third pass adds the forward decls needed to resolve circular defn problems
+	Pass<GenSetDtor>::run( translationUnit, structDecls, torDecls );
 }
-
 
 } // namespace Virtual
