Index: doc/LaTeXmacros/common.sty
===================================================================
--- doc/LaTeXmacros/common.sty	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/LaTeXmacros/common.sty	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -11,6 +11,6 @@
 %% Created On       : Sat Apr  9 10:06:17 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Sun Feb 25 23:30:09 2024
-%% Update Count     : 645
+%% Last Modified On : Thu Apr 18 09:14:02 2024
+%% Update Count     : 657
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -108,8 +108,11 @@
 \renewcommand\subparagraph{\@startsection{subparagraph}{4}{\z@}{-1.5ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries\itshape}}
 
-% index macros
 \newcommand{\italic}[1]{\emph{\hyperpage{#1}}}
 \newcommand{\Definition}[1]{\textbf{\hyperpage{#1}}}
-\newcommand{\see}[1]{(see #1)}
+\newcommand{\see}{\protect\@ifstar\@ssee\@see}
+\newcommand{\@ssee}[1]{(See #1)}
+\newcommand{\@see}[1]{(see #1)}
+
+% index macros
 
 % Define some commands that produce formatted index entries suitable for cross-references.
@@ -152,6 +155,6 @@
 \newcommand{\newtermFontInline}{\emph}
 \newcommand{\newterm}{\protect\@ifstar\@snewterm\@newterm}
+\newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
 \newcommand{\@newterm}[2][\@empty]{\lowercase{\def\temp{#2}}{\newtermFontInline{#2}}\ifx#1\@empty\index{\temp}\else\index{#1@{\protect#2}}\fi}
-\newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
 
 % \snake{<identifier>}
@@ -202,6 +205,7 @@
 
 \newenvironment{cquote}{%
-	\list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}%
+	\list{}{\topsep=\lst@aboveskip\parskip=0pt\partopsep=0pt\itemsep=0pt\parsep=0pt\listparindent=0pt\leftmargin=\parindentlnth\rightmargin=0pt}%
 	\item\relax
+	\lstset{resetmargins=true}
 }{%
 	\endlist
@@ -345,4 +349,6 @@
 \fi%
 
+\usepackage{tabularx}					% if @ is used for lstMakeShortInline, allows @{}
+
 % Local Variables: %
 % tab-width: 4 %
Index: doc/LaTeXmacros/common.tex
===================================================================
--- doc/LaTeXmacros/common.tex	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/LaTeXmacros/common.tex	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -11,6 +11,6 @@
 %% Created On       : Sat Apr  9 10:06:17 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Mon Feb 26 08:06:05 2024
-%% Update Count     : 615
+%% Last Modified On : Thu Apr 18 09:15:38 2024
+%% Update Count     : 664
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -109,8 +109,11 @@
 \renewcommand\subparagraph{\@startsection{subparagraph}{4}{\z@}{-1.5ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries\itshape}}
 
-% index macros
 \newcommand{\italic}[1]{\emph{\hyperpage{#1}}}
 \newcommand{\Definition}[1]{\textbf{\hyperpage{#1}}}
-\newcommand{\see}[1]{(see #1)}
+\newcommand{\see}{\protect\@ifstar\@ssee\@see}
+\newcommand{\@ssee}[1]{(See #1)}
+\newcommand{\@see}[1]{(see #1)}
+
+% index macros
 
 % Define some commands that produce formatted index entries suitable for cross-references.
@@ -153,6 +156,6 @@
 \newcommand{\newtermFontInline}{\emph}
 \newcommand{\newterm}{\protect\@ifstar\@snewterm\@newterm}
+\newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
 \newcommand{\@newterm}[2][\@empty]{\lowercase{\def\temp{#2}}{\newtermFontInline{#2}}\ifx#1\@empty\index{\temp}\else\index{#1@{\protect#2}}\fi}
-\newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
 
 % \snake{<identifier>}
@@ -201,12 +204,13 @@
 \newcommand{\VS}{\abbrevFont{vs}}
 \newcommand{\vs}{\VS\CheckPeriod}
-\makeatother
 
 \newenvironment{cquote}{%
-	\list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}%
+	\list{}{\topsep=\lst@aboveskip\parskip=0pt\partopsep=0pt\itemsep=0pt\parsep=0pt\listparindent=0pt\leftmargin=\parindentlnth\rightmargin=0pt}%
 	\item\relax
+	\lstset{resetmargins=true}
 }{%
 	\endlist
 }% cquote
+\makeatother
 
 \newenvironment{rationale}{%
@@ -349,4 +353,6 @@
 \fi%
 
+\usepackage{tabularx}					% if @ is used for lstMakeShortInline, allows @{}
+
 % Local Variables: %
 % tab-width: 4 %
Index: doc/LaTeXmacros/lstlang.sty
===================================================================
--- doc/LaTeXmacros/lstlang.sty	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/LaTeXmacros/lstlang.sty	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -8,6 +8,6 @@
 %% Created On       : Sat May 13 16:34:42 2017
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Tue Mar 12 17:29:58 2024
-%% Update Count     : 42
+%% Last Modified On : Mon Apr 15 11:28:44 2024
+%% Update Count     : 43
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -116,5 +116,5 @@
 		alignas, _Alignas, alignof, _Alignof, __alignof, __alignof__, and, asm, __asm, __asm__, _Atomic, __attribute, __attribute__,
 		__auto_type, basetypeof, _Bool, catch, catchResume, choose, coerce, corun, cofor, _Complex, __complex, __complex__,
-		__const, __const__, continue, _Decimal32, _Decimal64, _Decimal128, disable, dtype, enable, exception, __extension__,
+		__const, __const__, continue, coroutine, _Decimal32, _Decimal64, _Decimal128, disable, dtype, enable, exception, __extension__,
 		fallthrough, fallthru, finally, fixup, __float80, float80, __float128, float128, _Float16, _Float32, _Float32x, _Float64,
 		_Float64x, _Float128, _Float128x, forall, fortran, ftype, generator, _Generic, _Imaginary, __imag, __imag__, inline,
Index: doc/bibliography/pl.bib
===================================================================
--- doc/bibliography/pl.bib	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/bibliography/pl.bib	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -519,4 +519,14 @@
     year	= 1963,
     pages	= {1-17},
+}
+
+@misc{AlgolW,
+    keywords	= {AlgolW},
+    contributer	= {pabuhr@plg},
+    author	= {Henry Bauer and Sheldon Becker and Susan L. Graham and Edwin Satterthwaite and Richard L. Sites},
+    title	= {{Algol W} Language Description},
+    month	= jun,
+    year	= 1972,
+    howpublished= {\url{https://www.algol60.org/docsW/algolw.pdf}},
 }
 
Index: doc/theses/jiada_liang_MMath/CFAenum.tex
===================================================================
--- doc/theses/jiada_liang_MMath/CFAenum.tex	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/theses/jiada_liang_MMath/CFAenum.tex	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -137,5 +137,5 @@
 \section{Pure Enumerators}
 
-An empty enumerator type, @enum()@, implies the enumerators are pure symbols without values but set properties;
+An empty enumerator type, @enum()@, implies the enumerators are opaque symbols without values but set properties;
 hence, there is no default conversion to @int@. 
 
Index: doc/theses/jiada_liang_MMath/Makefile
===================================================================
--- doc/theses/jiada_liang_MMath/Makefile	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/theses/jiada_liang_MMath/Makefile	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -13,6 +13,6 @@
 BibSRC = ${wildcard *.bib}
 
-TeXLIB = .:${LaTMac}:${Build}:
-BibLIB = .:${BibRep}:
+TeXLIB = .:${LaTMac}:${Build}:			# common latex macros
+BibLIB = .:${BibRep}:				# common citation repository
 
 MAKEFLAGS = --no-print-directory # --silent
Index: doc/theses/jiada_liang_MMath/background.tex
===================================================================
--- doc/theses/jiada_liang_MMath/background.tex	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/theses/jiada_liang_MMath/background.tex	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -1,4 +1,3 @@
 \chapter{Background}
-\lstnewenvironment{clang}[1][]{\lstset{language=[ANSI]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 \CFA is a backwards-compatible extension of the C programming language.
@@ -48,6 +47,29 @@
 
 \section{C Enumeration}
+\label{s:CEnumeration}
 
-The C enumeration has the following syntax and semantics.
+The C enumeration has the following syntax~\cite[\S~6.7.2.2]{C11}.
+\begin{clang}[identifierstyle=\linespread{0.9}\it]
+$\it enum$-specifier:
+	enum identifier$\(_{opt}\)$ { enumerator-list }
+	enum identifier$\(_{opt}\)$ { enumerator-list , }
+	enum identifier
+enumerator-list:
+	enumerator
+	enumerator-list , enumerator
+enumerator:
+	enumeration-constant
+	enumeration-constant = constant-expression
+\end{clang}
+The terms \emph{enumeration} and \emph{enumerator} used in this work \see{\VRef{s:Terminology}} come from the grammar.
+The C enumeration semantics is discussed using examples.
+
+An unnamed enumeration is used to provide secondary renaming, like a @const@ declaration in other languages.
+\begin{clang}
+enum { Size = 20, Pi = 3.14159 };   // unnamed enumeration $\(\Rightarrow\)$ no ordering
+\end{clang}
+This declaration form is not an enumeration even though it is declared using an @enum@ because it has none of the following enumeration properties.
+
+A \emph{named} enumeration type is an actual enumeration.
 \begin{clang}
 enum Weekday { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun, };
Index: doc/theses/jiada_liang_MMath/intro.tex
===================================================================
--- doc/theses/jiada_liang_MMath/intro.tex	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/theses/jiada_liang_MMath/intro.tex	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -1,27 +1,28 @@
 \chapter{Introduction}
 
-All types in a programming language must have a set of constants, and these constants have \Newterm{primary names}, \eg integral types have constants @-1@, @17@, @12345@, \etc.
-Constants can be overloaded among types, \eg @0@ is a null pointer for all pointer types, and the value zero for integral and floating-point types.
+All types in a programming language must have a set of constants, and these constants have \Newterm{primary names}, \eg integral types have constants @-1@, @17@, @0xff@, floating-point types have constants @5.3@, @2.3E-5@, @0xff.ffp0@, character types have constants @'a'@, @"abc\n"@, \mbox{\lstinline{u8"}\texttt{\guillemotleft{na\"{i}ve}\guillemotright}\lstinline{"}}, \etc.
+Con\-stants can be overloaded among types, \eg @0@ is a null pointer for all pointer types, and the value zero for integral and floating-point types.
+(In \CFA, the primary constants @0@ and @1@ can be overloaded for any type.)
 Hence, each primary constant has a symbolic name referring to its internal representation, and these names are dictated by language syntax related to types.
-In theory, there are an infinite set of primary names per type.
-
-\Newterm{Secondary naming} is a common practice in mathematics and engineering, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MHz (1E6), and in general situations, \eg specific times (noon, New Years), cities (Big Apple), flowers (Lily), \etc.
+In theory, there are an infinite set of primary constant names per type.
+
+\Newterm{Secondary naming} is a common practice in mathematics, engineering and computer science, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MB (megabyte, 1E6), and in general situations, \eg specific times (noon, New Years), cities (Big Apple), flowers (Lily), \etc.
 Many programming languages capture this important software-engineering capability through a mechanism called \Newterm{constant} or \Newterm{literal} naming, where a secondary name is aliased to a primary name.
-In some cases, secondary naming is \Newterm{pure}, where the matching internal representation can be chosen arbitrarily, and only equality operations are available, \eg @O_RDONLY@, @O_WRONLY@, @O_CREAT@, @O_TRUNC@, @O_APPEND@.
-(The names the thing.)
+Its purpose is for readability and to eliminate duplication of the primary constant throughout a program.
+For example, a meaningful secondary name replaces a primary name throughout a program;
+thereafter, changing the binding of the secondary to primary name automatically distributes the rebinding, preventing errors.
+In some cases, secondary naming is \Newterm{opaque}, where the matching internal representation can be chosen arbitrarily, and only equality operations are available, \eg @O_RDONLY@, @O_WRONLY@, @O_CREAT@, @O_TRUNC@, @O_APPEND@.
 Because a secondary name is a constant, it cannot appear in a mutable context, \eg \mbox{$\pi$ \lstinline{= 42}} is meaningless, and a constant has no address, \ie it is an \Newterm{rvalue}\footnote{
 The term rvalue defines an expression that can only appear on the right-hand side of an assignment expression.}.
 
-Secondary names can form an (ordered) set, \eg days of the week, months of a year, floors of a building (basement, ground, 1st), colours in a rainbow, \etc.
+Secondary names can form an (ordered) set, \eg days of a week, months of a year, floors of a building (basement, ground, 1st), colours in a rainbow, \etc.
 Many programming languages capture these groupings through a mechanism called an \Newterm{enumeration}.
 \begin{quote}
 enumerate (verb, transitive).
 To count, ascertain the number of;
-\emph{more
-usually, to mention (a number of things or persons) separately, as if for the
-purpose of counting};
-to specify as in a list or catalogue.~\cite{OED}
+more usually, to mention (a number of things or persons) separately, as if for the purpose of counting;
+to specify as in a list or catalogue.~\cite{OEDenumerate}
 \end{quote}
-Within an enumeration set, the enumeration names must be unique, and instances of an enumerated type are restricted to hold only the secondary names.
+Within an enumeration set, the enumeration names must be unique, and instances of an enumerated type are \emph{often} restricted to hold only the secondary names.
 It is possible to enumerate among set names without having an ordering among the set elements.
 For example, the week, the weekdays, the weekend, and every second day of the week.
@@ -29,29 +30,48 @@
 for ( cursor in Mon, Tue, Wed, Thu, Fri, Sat, Sun } ... $\C[3.75in]{// week}$
 for ( cursor in Mon, Tue, Wed, Thu, Fri } ...	$\C{// weekday}$
-for ( cursor in Thu, Fri } ...					$\C{// weekend}$
+for ( cursor in Sat, Sun } ...					$\C{// weekend}$
 for ( cursor in Mon, Wed, Fri, Sun } ...		$\C{// every second day of week}\CRT$
 \end{cfa}
-This independence from internal representation allows multiple names to have the same representation (eight note, quaver), giving synonyms.
+This independence from internal representation allows multiple names to have the same representation (eighth note, quaver), giving synonyms.
 A set can have a partial or total ordering, making it possible to compare set elements, \eg Monday is before Friday and Friday is after.
-Ordering allows iterating among the enumeration set using relational operators and advancement, \eg
+Ordering allows iterating among the enumeration set using relational operators and advancement, \eg:
 \begin{cfa}
 for ( cursor = Monday; cursor @<=@ Friday; cursor = @succ@( cursor ) ) ...
 \end{cfa}
-Here the internal representations for the secondary names are \emph{generated} rather than listing a subset of names.
+Here the internal representation for the secondary names are logically \emph{generated} rather than listing a subset of names.
+
+Hence, the fundamental aspects of an enumeration are:
+\begin{enumerate}
+\item
+\begin{sloppypar}
+It provides a finite set of secondary names, which become its primary constants.
+This differentiates an enumeration from general types with an infinite set
+of primary constants.
+\end{sloppypar}
+\item
+The secondary names are constants, which follows transitively from their binding (aliasing) to primary names, which are constants.
+\item
+Defines a type for generating instants (variables).
+\item
+For safety, an enumeration instance should be restricted to hold only its type's secondary names.
+\item
+There is a mechanism for \emph{enumerating} over the secondary names, where the ordering can be implicit from the type, explicitly listed, or generated arithmetically.
+\end{enumerate}
 
 
 \section{Terminology}
-
-The term \Newterm{enumeration} defines the set of secondary names, and the term \Newterm{enumerator} represents an arbitrary secondary name.
-As well, an enumerated type has three fundamental properties, \Newterm{label}, \Newterm{order}, and \Newterm{value}.
+\label{s:Terminology}
+
+The term \Newterm{enumeration} defines a type with a set of secondary names, and the term \Newterm{enumerator} represents an arbitrary secondary name \see{\VRef{s:CEnumeration} for the name derivation}.
+As well, an enumerated type can have three fundamental properties, \Newterm{label}, \Newterm{order}, and \Newterm{value}.
 \begin{cquote}
 \sf\setlength{\tabcolsep}{3pt}
 \begin{tabular}{rcccccccr}
 \it\color{red}enumeration	& \multicolumn{8}{c}{\it\color{red}enumerators}	\\
-$\downarrow$\hspace*{25pt}	& \multicolumn{8}{c}{$\downarrow$}				\\
-@enum@ Week \{				& Mon,	& Tue,	& Wed,	& Thu,	& Fri, 	& Sat,	& Sun = 42	& \};	\\
+$\downarrow$\hspace*{15pt}	& \multicolumn{8}{c}{$\downarrow$}				\\
+@enum@ Week \{				& Mon,	& Tue,	& Wed,	& Thu,	& Fri, 	& Sat,	& Sun {\color{red}= 42}	& \};	\\
 \it\color{red}label			& Mon	& Tue	& Wed	& Thu	& Fri 	& Sat	& Sun		&		\\
 \it\color{red}order			& 0		& 1		& 2		& 3		& 4		& 5		& 6	 		&		\\
-\it\color{red}value			& 0		& 1		& 2		& 3		& 4		& 5		& 42 		&
+\it\color{red}value			& 0		& 1		& 2		& 3		& 4		& 5		& {\color{red}42} 		&
 \end{tabular}
 \end{cquote}
@@ -72,99 +92,169 @@
 \section{Motivation}
 
-Some programming languages only provide secondary renaming, which can be simulated by an enumeration without ordering.
-\begin{cfa}
-const Size = 20, Pi = 3.14159;
-enum { Size = 20, Pi = 3.14159 };   // unnamed enumeration $\(\Rightarrow\)$ no ordering
-\end{cfa}
-In both cases, it is possible to compare the secondary names, \eg @Size < Pi@, if that is meaningful;
-however, without an enumeration type-name, it is impossible to create an iterator cursor.
-
-Secondary renaming can similate an enumeration, but with extra effort.
+Many programming languages provide an enumeration-like mechanism, which may or may not cover the previous five fundamental enumeration aspects.
+Hence, the term \emph{enumeration} can be confusing and misunderstood.
+Furthermore, some languages conjoin the enumeration with other type features, making it difficult to tease apart which featuring is being used.
+This section discusses some language features that are sometimes called an enumeration but do not provide all enumeration aspects.
+
+
+\subsection{Aliasing}
+
+Some languages provide simple secondary aliasing (renaming), \eg:
+\begin{cfa}
+const Size = 20, Pi = 3.14159, Name = "Jane";
+\end{cfa}
+The secondary name is logically replaced in the program text by its corresponding primary name.
+Therefore, it is possible to compare the secondary names, \eg @Size < Pi@, only because the primary constants allow it, whereas \eg @Pi < Name@ might be disallowed depending on the language.
+
+Aliasing is not macro substitution, \eg @#define Size 20@, where a name is replaced by its value \emph{before} compilation, so the name is invisible to the programming language.
+With aliasing, each secondary name is part of the language, and hence, participates fully, such as name overloading in the type system.
+Aliasing is not an immutable variable, \eg:
+\begin{cfa}
+extern @const@ int Size = 20;
+extern void foo( @const@ int @&@ size );
+foo( Size ); // take the address of (reference) Size
+\end{cfa}
+Taking the address of an immutable variable makes it an \Newterm{lvalue}, which implies it has storage.
+With separate compilation, it is necessary to choose one translation unit to perform the initialization.
+If aliasing does require storage, its address and initialization are opaque (compiler only), similar to \CC rvalue reference @&&@.
+
+Aliasing does provide readability and automatic resubstitution.
+It also provides simple enumeration properties, but with extra effort.
 \begin{cfa}
 const Mon = 1, Tue = 2, Wed = 3, Thu = 4, Fri = 5, Sat = 6, Sun = 7;
 \end{cfa}
-Furthermore, reordering the enumerators requires manual renumbering.
+Any reordering of the enumerators requires manual renumbering.
 \begin{cfa}
 const Sun = 1, Mon = 2, Tue = 3, Wed = 4, Thu = 5, Fri = 6, Sat = 7;
 \end{cfa}
-Finally, there is no common type to create a type-checked instance or iterator cursor.
-Hence, there is only a weak equivalence between secondary naming and enumerations, justifying the enumeration type in a programming language.
-
-A variant (algebraic) type is often promoted as a kind of enumeration, \ie a varient type can simulate an enumeration.
-A variant type is a tagged-union, where the possible types may be heterogeneous.
-\begin{cfa}
-@variant@ Variant {
-	@int tag;@  // optional/implicit: 0 => int, 1 => double, 2 => S
-	@union {@ // implicit
-		case int i;
-		case double d;
-		case struct S { int i, j; } s;
-	@};@
-};
-\end{cfa}
-Crucially, the union implies instance storage is shared by all of the variant types.
-Hence, a variant is dynamically typed, as in a dynamic-typed programming-language, but the set of types is statically bound, similar to some aspects of dynamic gradual-typing~\cite{Gradual Typing}.
-Knowing which type is in a variant instance is crucial for correctness.
-Occasionally, it is possible to statically determine all regions where each variant type is used, so a tag and runtime checking is unnecessary;
-otherwise, a tag is required to denote the particular type in the variant and the tag checked at runtime using some form of type pattern-matching.
-
-The tag can be implicitly set by the compiler on assignment, or explicitly set by the program\-mer.
-Type pattern-matching is then used to dynamically test the tag and branch to a section of code to safely manipulate the value, \eg:
-\begin{cfa}[morekeywords={match}]
-Variant v = 3;  // implicitly set tag to 0
-@match@( v ) {    // know the type or test the tag
-	case int { /* only access i field in v */ }
-	case double { /* only access d field in v */ }
-	case S { /* only access s field in v */ }
-}
-\end{cfa}
-For safety, either all variant types must be listed or a @default@ case must exist with no field accesses.
-
-To simulate an enumeration with a variant, the tag is \emph{re-purposed} for either ordering or value and the variant types are omitted.
-\begin{cfa}
-variant Weekday {
-	int tag; // implicit 0 => Mon, ..., 6 => Sun
-	@case Mon;@ // no type
-	...
-	@case Sun;@
-};
-\end{cfa}
-The type system ensures tag setting and testing are correctly done.
-However, the enumeration operations are limited to the available tag operations, \eg pattern matching.
-\begin{cfa}
-Week week = Mon;
-if ( @dynamic_cast(Mon)@week ) ... // test tag == Mon
-\end{cfa}
-While enumerating among tag names is possible:
-\begin{cfa}[morekeywords={in}]
-for ( cursor in Mon, Wed, Fri, Sun ) ...
-\end{cfa}
-ordering for iteration would require a \emph{magic} extension, such as a special @enum@ variant, because it has no meaning for a regular variant, \ie @int@ < @double@.
-
-However, if a special @enum@ variant allows the tags to be heterogeneously typed, ordering must fall back on case positioning, as many types have incomparable values.
-Iterating using tag ordering and heterogeneous types, also requires pattern matching.
-\begin{cfa}[morekeywords={match}]
-for ( cursor = Mon; cursor <= Fri; cursor = succ( cursor) ) {
-	match( cursor ) {
-		case Mon { /* access special type for Mon */ }
-		...
-		case Fri { /* access special type for Fri */ }
-		default
-	}
-}
-\end{cfa}
-If the variant type is changed by adding/removing types or the loop range changes, the pattern matching must be adjusted.
-As well, if the start/stop values are dynamic, it may be impossible to statically determine if all variant types are listed. 
-
-Re-purposing the notion of enumerating into variant types is ill formed and confusing.
-Hence, there is only a weak equivalence between an enumeration and variant type, justifying the enumeration type in a programming language.
+For these reasons, aliasing is sometimes called an enumeration.
+However, there is no type to create a type-checked instance or iterator cursor, so there is no ability for enumerating.
+Hence, there are multiple enumeration aspects not provided by aliasing, justifying a separate enumeration type in a programming language.
+
+
+\subsection{Algebraic Data Type}
+
+An algebraic data type (ADT)\footnote{ADT is overloaded with abstract data type.} is another language feature often linked with enumeration, where an ADT conjoins an arbitrary type, possibly a \lstinline[language=C++]{class} or @union@, and a named constructor.
+For example, in Haskell:
+\begin{haskell}
+data S = S { i::Int, d::Double }		$\C{// structure}$
+data @Foo@ = A Int | B Double | C S		$\C{// ADT, composed of three types}$
+foo = A 3;								$\C{// type Foo is inferred}$
+bar = B 3.5
+baz = C S{ i = 7, d = 7.5 }
+\end{haskell}
+the ADT has three variants (constructors), @A@, @B@, @C@ with associated types @Int@, @Double@, and @S@.
+The constructors create an initialized value of the specific type that is bound to the immutable variables @foo@, @bar@, and @baz@.
+Hence, the ADT @Foo@ is like a union containing values of the associated types, and a constructor name is used to access the value using dynamic pattern-matching.
+\begin{cquote}
+\setlength{\tabcolsep}{15pt}
+\begin{tabular}{@{}ll@{}}
+\begin{haskell}
+prtfoo val = -- function
+    -- pattern match on constructor
+    case val of
+      @A@ a -> print a
+      @B@ b -> print b
+      @C@ (S i d) -> do
+          print i
+          print d
+\end{haskell}
+&
+\begin{haskell}
+main = do
+    prtfoo foo
+    prtfoo bar
+    prtfoo baz
+3
+3.5
+7
+7.5
+\end{haskell}
+\end{tabular}
+\end{cquote}
+For safety, most languages require all assocaited types to be listed or a default case with no field accesses.
+
+A less frequent case is multiple constructors with the same type.
+\begin{haskell}
+data Bar = X Int | Y Int | Z Int;
+foo = X 3;
+bar = Y 3;
+baz = Z 5;
+\end{haskell}
+Here, the constructor name gives different meaning to the values in the common \lstinline[language=Haskell]{Int} type, \eg the value @3@ has different interpretations depending on the constructor name in the pattern matching.
+
+Note, the term \Newterm{variant} is often associated with ADTs.
+However, there are multiple languages with a @variant@ type that is not an ADT \see{Algol68~\cite{Algol68} or \CC \lstinline{variant}}.
+In these languages, the variant is often a union using RTTI tags, which cannot be used to simulate an enumeration.
+Hence, in this work the term variant is not a synonym for ADT.
+
+% https://downloads.haskell.org/ghc/latest/docs/libraries/base-4.19.1.0-179c/GHC-Enum.html
+% https://hackage.haskell.org/package/base-4.19.1.0/docs/GHC-Enum.html
+
+The association between ADT and enumeration occurs if all the constructors have a unit (empty) type, \eg @struct unit {}@.
+Note, the unit type is not the same as \lstinline{void}, \eg:
+\begin{cfa}
+void foo( void );
+struct unit {} u;  // empty type
+unit bar( unit );
+foo( foo() );        // void argument does not match with void parameter
+bar( bar( u ) );   // unit argument does match with unit parameter
+\end{cfa}
+
+For example, in the Haskell ADT:
+\begin{haskell}
+data Week = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving(Enum, Eq, Show)
+\end{haskell}
+the default type for each constructor is the unit type, and deriving from @Enum@ enforces no other type, @Eq@ allows equality comparison, and @Show@ is for printing.
+The nullary constructors for the unit types are numbered left-to-right from $0$ to @maxBound@$- 1$, and provides enumerating operations @succ@, @pred@, @enumFrom@ @enumFromTo@.
+\VRef[Figure]{f:HaskellEnumeration} shows enumeration comparison and iterating (enumerating).
+
+\begin{figure}
+\begin{cquote}
+\setlength{\tabcolsep}{15pt}
+\begin{tabular}{@{}ll@{}}
+\begin{haskell}
+day = Tue
+main = do
+    if day == Tue then
+        print day
+    else
+        putStr "not Tue"
+    print (enumFrom Mon)            -- week
+    print (enumFromTo Mon Fri)   -- weekday
+    print (enumFromTo Sat Sun)  -- weekend
+\end{haskell}
+&
+\begin{haskell}
+Tue
+[Mon,Tue,Wed,Thu,Fri,Sat,Sun]
+[Mon,Tue,Wed,Thu,Fri]
+[Sat,Sun]
+
+
+
+
+
+\end{haskell}
+\end{tabular}
+\end{cquote}
+\caption{Haskell Enumeration}
+\label{f:HaskellEnumeration}
+\end{figure}
+
+The key observation is the dichotomy between an ADT and enumeration: the ADT uses the associated type resulting in a union-like data structure, and the enumeration does not use the associated type, and hence, is not a union.
+While the enumeration is constructed using the ADT mechanism, it is so restricted it is not really an ADT.
+Furthermore, a general ADT cannot be an enumeration because the constructors generate different values making enumerating meaningless.
+While functional programming languages regularly repurpose the ADT type into an enumeration type, this process seems contrived and confusing.
+Hence, there is only a weak equivalence between an enumeration and ADT, justifying a separate enumeration type in a programming language.
 
 
 \section{Contributions}
 
-The goal of this work is to to extend the simple and unsafe enumeration type in the C programming-language into a sophisticated and safe type in the \CFA programming-language, while maintain backwards compatibility with C.
+The goal of this work is to to extend the simple and unsafe enumeration type in the C programming-language into a complex and safe enumeration type in the \CFA programming-language, while maintaining backwards compatibility with C.
 On the surface, enumerations seem like a simple type.
 However, when extended with advanced features, enumerations become complex for both the type system and the runtime implementation.
 
+The contribution of this work are:
 \begin{enumerate}
 \item
@@ -175,5 +265,5 @@
 typing
 \item
-subset
+subseting
 \item
 inheritance
Index: doc/theses/jiada_liang_MMath/relatedwork.tex
===================================================================
--- doc/theses/jiada_liang_MMath/relatedwork.tex	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/theses/jiada_liang_MMath/relatedwork.tex	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -23,5 +23,4 @@
 \section{Pascal}
 \label{s:Pascal}
-\lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
@@ -51,31 +50,17 @@
 
 \section{Ada}
-\lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
-
-An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
+
+An Ada enumeration type is a set of ordered unscoped identifiers (enumerators) bound to \emph{unique} \Newterm{literals}.\footnote{%
+Ada is \emph{case-insensitive} so identifiers may appear in multiple forms and still be the same, \eg \lstinline{Mon}, \lstinline{moN}, and \lstinline{MON} (a questionable design decision).}
 \begin{ada}
-type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
+type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun ); -- literals (enumerators)
 \end{ada}
 Object initialization and assignment are restricted to the enumerators of this type.
-Enumerators without an explicitly designated constant value are auto-initialized: from left to right, starting at zero or the next explicitly initialized constant, incrementing by 1.
-To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
+While Ada enumerators are unscoped, like C, Ada enumerators are overloadable.
 \begin{ada}
-type RGB is ( Red, Green, Blue );
-@for RGB use ( Red => 10, Green => 20, Blue => 30 );@ -- ascending order
-\end{ada}
-Hence, the position, value, label tuples are:
-\begin{ada}
-(0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE) 
-\end{ada}
-Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same, \eg @Red@ and @RED@ (a questionable design decision).
-
-Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
-The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of enumerators, which is always ascending.
-
-Ada enumerators are overloadable.
-\begin{ada}
+type RGB is ( @Red@, @Green@, Blue );
 type Traffic_Light is ( @Red@, Yellow, @Green@ );
 \end{ada}
-Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
+Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded identifiers.
 \VRef[Figure]{f:AdaEnumeration} shows how ambiguity is handled using a cast, \ie \lstinline[language=ada]{RGB'(Red)}.
 
@@ -102,5 +87,13 @@
 \end{figure}
 
-Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package names.
+Enumerators without initialization are auto-initialized from left to right, starting at zero, incrementing by 1.
+Enumerators with initialization must set \emph{all} enumerators in \emph{ascending} order, \ie there is no auto-initialization.
+\begin{ada}
+type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
+for Week use ( Mon => 0, Tue => 1, Wed => 2, Thu => @10@, Fri => 11, Sat => 14, Sun => 15 );
+\end{ada}
+The enumeration operators are the equality and relational operators, @=@, @/=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of acsending enumerators.
+
+Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package identifiers.
 \begin{ada}
 OtherRed : RGB renames Red;
@@ -113,5 +106,4 @@
 There are three pairs of inverse enumeration pseudo-functions (attributes): @'Pos@ and @'Val@, @'Enum_Rep@ and @'Enum_Val@, and @'Image@ and @'Value@,
 \begin{cquote}
-\lstDeleteShortInline@
 \setlength{\tabcolsep}{15pt}
 \begin{tabular}{@{}ll@{}}
@@ -128,5 +120,4 @@
 \end{ada}
 \end{tabular}
-\lstMakeShortInline@
 \end{cquote}
 These attributes are important for IO.
@@ -138,5 +129,5 @@
 \end{ada}
 which is syntactic sugar for the label and not character literals from the predefined type @Character@.
-The purpose is strictly readability using character literals rather than names.
+The purpose is strictly readability using character literals rather than identifiers.
 \begin{ada}
 Op : Operator := '+';
@@ -171,5 +162,4 @@
 An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
 \begin{cquote}
-\lstDeleteShortInline@
 \setlength{\tabcolsep}{15pt}
 \begin{tabular}{@{}ll@{}}
@@ -211,5 +201,4 @@
 \end{ada}
 \end{tabular}
-\lstMakeShortInline@
 \end{cquote}
 
@@ -225,9 +214,8 @@
 \section{\CC}
 \label{s:C++RelatedWork}
-\lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 \CC has the equivalent of Pascal typed @const@ declarations \see{\VRef{s:Pascal}}, with static and dynamic initialization.
 \begin{c++}
-const auto one = 0 + 1;					$\C{// static intialization}$
+const auto one = 0 + 1;					$\C{// static initialization}$
 const auto NULL = nullptr;
 const auto PI = 3.14159;
@@ -237,5 +225,5 @@
 				Sat = Fri + 1, Sun = Sat + 1;
 int sa[Sun];
-const auto r = random();				$\C{// dynamic intialization}$
+const auto r = random();				$\C{// dynamic initialization}$
 int da[r];								$\C{// VLA}$
 \end{c++}
@@ -319,5 +307,4 @@
 \section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
 \label{s:Csharp}
-\lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 % https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
@@ -362,5 +349,4 @@
 \begin{figure}
 \centering
-\lstDeleteShortInline@
 \begin{tabular}{@{}l|l@{}}
 \multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
@@ -414,5 +400,4 @@
 \end{csharp}
 \end{tabular}
-\lstMakeShortInline@
 \caption{\Csharp: Free Routine Versus Class Enumeration}
 \label{CsharpFreeVersusClass}
@@ -421,5 +406,4 @@
 
 \section{Golang}
-\lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 Golang provides pseudo-enumeration similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
@@ -429,5 +413,5 @@
 const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$
 \end{Go}
-Constant names are unscoped and must be unique (no overloading).
+Constant identifiers are unscoped and must be unique (no overloading).
 The first enumerator \emph{must} be explicitly initialized;
 subsequent enumerators can be implicitly or explicitly initialized.
@@ -459,5 +443,4 @@
 Basic switch and looping are possible.
 \begin{cquote}
-\lstDeleteShortInline@
 \setlength{\tabcolsep}{15pt}
 \begin{tabular}{@{}ll@{}}
@@ -482,5 +465,4 @@
 \end{Go}
 \end{tabular}
-\lstMakeShortInline@
 \end{cquote}
 However, the loop prints the values from 0 to 13 because there is no actual enumeration.
@@ -488,6 +470,4 @@
 
 \section{Java}
-\lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
-	escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
 
 Every enumeration in Java is an enumeration class.
@@ -513,5 +493,4 @@
 \begin{figure}
 \centering
-\lstDeleteShortInline@
 \begin{tabular}{@{}l|l@{}}
 \multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
@@ -553,5 +532,4 @@
 \end{Java}
 \end{tabular}
-\lstMakeShortInline@
 \caption{Java: Free Routine Versus Class Enumeration}
 \label{f:JavaFreeVersusClass}
@@ -606,5 +584,5 @@
 
 \section{Rust}
-\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+% https://doc.rust-lang.org/reference/items/enumerations.html
 
 Rust provides a scoped enumeration based on variant types.
@@ -652,5 +630,4 @@
 
 \section{Swift}
-\lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 % https://www.programiz.com/swift/online-compiler
@@ -1010,73 +987,64 @@
 
 
-\section{Python}
-\lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
-
-A Python enumeration is a set of symbolic names bound to \emph{unique} values.
-They are similar to global variables, but offer a more useful @repr()@, grouping, type-safety, and additional features.
-Enumerations inherits from the @Enum@ class, \eg:
-\begin{python}
-class Weekday(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
-class RGB(@Enum@): Red = 1; Green = 2; Blue = 3
-\end{python}
-
-Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member:
-\begin{python}
-print( repr( Weekday( 3 ) ) )
-<Weekday.Wed: 3>
-\end{python}
-As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
-The @str()@ of a member shows only the enum name and member name:
-\begin{python}
-print( str( Weekday.Thu ), Weekday.Thu )
-Weekday.Thu Weekday.Thu
-\end{python}
-The type of an enumeration member is the enum it belongs to:
-\begin{python}
-print( type( Weekday.Thu ) )
-<enum 'Weekday'>
-print( isinstance(Weekday.Fri, Weekday) )
-True
-\end{python}
-Enum members have an attribute that contains just their name:
-\begin{python}
-print(Weekday.TUESDAY.name)
-TUESDAY
-\end{python}
-Likewise, they have an attribute for their value:
-\begin{python}
-Weekday.WEDNESDAY.value
-3
-\end{python}
-
-Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
-For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
-The difference is that one of them counts from 0-6 and the other from 1-7.
-Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member:
-\begin{python}
-class Weekday(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = 15; Sat = 16; Sun = 17
-$@$classmethod
-def from_date(cls, date):
-	return cls(date.isoweekday())
-\end{python}
-Now we can find out what today is! Observe:
-\begin{python}
->>> from datetime import date
->>> Weekday.from_date(date.today())     
-<Weekday.TUESDAY: 2>
-\end{python}
-Of course, if you're reading this on some other day, you'll see that day instead.
-
-This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@:
-\begin{python}
-from enum import Flag
-class WeekdayF(@Flag@): Mon = @1@; Tue = @2@; Wed = @4@; Thu = @8@; Fri = @16@; Sat = @32@; Sun = @64@
-\end{python}
-We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
+\section{Python 3.13}
+% https://docs.python.org/3/howto/enum.html
+
+Python is a dynamically-typed reflexive programming language with multiple versions, and hence, it is possible to extend existing or build new language features within the language.
+As a result, discussing Python enumerations is a moving target, because if a features does not exist, if can often be created with varying levels of complexity.
+Nevertheless, an attempt has been made to discuss core enumeration features that come with Python 3.13.
+
+A Python enumeration type is a set of ordered scoped identifiers (enumerators) bound to \emph{unique} values.
+An enumeration is not a basic type;
+it is a @class@ inheriting from the @Enum@ class, where the enumerators must be explicitly initialized, \eg:
+\begin{python}
+class Week(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
+\end{python}
+and/or explicitly auto initialized, \eg:
+\begin{python}
+class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @auto()@; Sat = 4; Sun = @auto()@
+\end{python}
+where @auto@ increments by 1 from the previous enumerator value.
+Object initialization and assignment are restricted to the enumerators of this type.
+An enumerator initialized with same value is an alias and invisible at the enumeration level, \ie the alias it substituted for its aliasee.
+\begin{python}
+class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @10@; Sat = @10@; Sun = @10@
+\end{python}
+Here, the enumeration has only 4 enumerators and 3 aliases.
+An alias is only visible by dropping down to the @class@ level and asking for class members.
+@Enum@ only supports equality comparison between enumerator values;
+the extended class @OrderedEnum@ adds relational operators @<@, @<=@, @>@, and @>=@.
+
+There are bidirectional enumeration pseudo-functions for label and value, but there is no concept of access using ordering (position).
+\begin{cquote}
+\setlength{\tabcolsep}{15pt}
+\begin{tabular}{@{}ll@{}}
+\begin{python}
+Week.Thu.value == 10;
+Week.Thu.name == 'Thu';
+\end{python}
+&
+\begin{python}
+Week( 10 ) == Thu
+Week['Thu'].value = 10
+\end{python}
+\end{tabular}
+\end{cquote}
+
+As an enumeration is a \lstinline[language=python]{class}, its own methods.
+\begin{python}
+class Week(Enum):
+	Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
+	$\\@$classmethod
+	def today(cls, date):
+		return cls(date.isoweekday())
+print( "today:", Week.today(date.today()))
+today: Week.Mon
+\end{python}
+The method @today@ retrieves the day of the week and uses it as an index to print out the corresponding label of @Week@.
 
 @Flag@ allows combining several members into a single variable:
 \begin{python}
-print( repr(WeekdayF.Sat | WeekdayF.Sun) )
-<WeekdayF.Sun|Sat: 96>
+print( repr(WeekF.Sat | WeekF.Sun) )
+<WeekF.Sun|Sat: 96>
 \end{python}
 You can even iterate over a @Flag@ variable:
@@ -1084,13 +1052,13 @@
 for day in weekend:
 	print(day)
-Weekday.SATURDAY
-Weekday.SUNDAY
+WeekF.Sat
+WeekF.Sun
 \end{python}
 Okay, let's get some chores set up:
 \begin{python}
 >>> chores_for_ethan = {
-...    'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,
-...    'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,
-...    'answer SO questions': Weekday.SATURDAY,
+...    'feed the cat': Week.MONDAY | Week.WEDNESDAY | Week.FRIDAY,
+...    'do the dishes': Week.TUESDAY | Week.THURSDAY,
+...    'answer SO questions': Week.SATURDAY,
 ...    }
 \end{python}
@@ -1101,19 +1069,14 @@
 ...        if day in days:
 ...            print(chore)
->>> show_chores(chores_for_ethan, Weekday.SATURDAY)
+>>> show_chores(chores_for_ethan, Week.SATURDAY)
 answer SO questions
 \end{python}
-In cases where the actual values of the members do not matter, you can save yourself some work and use @auto()@ for the values:
-\begin{python}
->>> from enum import auto
->>> class Weekday(Flag):
-...    MONDAY = auto()
-...    TUESDAY = auto()
-...    WEDNESDAY = auto()
-...    THURSDAY = auto()
-...    FRIDAY = auto()
-...    SATURDAY = auto()
-...    SUNDAY = auto()
-...    WEEKEND = SATURDAY | SUNDAY
+Auto incrmenet for @Flag@ is by powers of 2.
+\begin{python}
+class WeekF(Flag): Mon = auto(); Tue = auto(); Wed = auto(); Thu = auto(); Fri = auto();  \
+							Sat = auto(); Sun = auto(); Weekend = Sat | Sun
+for d in WeekF:
+	print( f"{d.name}: {d.value}", end=" ")
+Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16 Sat: 32 Sun: 64 WeekA.Weekend
 \end{python}
 
@@ -1123,44 +1086,19 @@
 @Enum@ allows such access:
 \begin{python}
->>> Color(1)
-<Color.RED: 1>
->>> Color(3)
-<Color.BLUE: 3>
+print(RGB(1), RGB(3), )
+RGB.RED RGB.GREEN
 \end{python}
 If you want to access enum members by name, use item access:
 \begin{python}
-Color['RED']
-<Color.RED: 1>
-
-Color['GREEN']
-<Color.GREEN: 2>
+print( RGBa['RED'], RGBa['GREEN'] )
+RGB.RED RGB.GREEN
 \end{python}
 If you have an enum member and need its name or value:
 \begin{python}
->>> member = Color.RED
->>> member.name
-'RED'
->>> member.value
-1
-\end{python}
-
-\subsection{Duplicating enum members and values}
-
-An enum member can have other names associated with it.
-Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
-By-value lookup of the value of @A@ will return the member @A@.
-By-name lookup of @A@ will return the member @A@.
-By-name lookup of @B@ will also return the member @A@:
-\begin{python}
-class Shape(Enum): SQUARE = 2; DIAMOND = 1; CIRCLE = 3; ALIAS_FOR_SQUARE = 2
->>> Shape.SQUARE
-<Shape.SQUARE: 2>
->>> Shape.ALIAS_FOR_SQUARE
-<Shape.SQUARE: 2>
->>> Shape(2)
-<Shape.SQUARE: 2>
-\end{python}
-
-Note: Attempting to create a member with the same name as an already defined attribute (another member, a method, etc.) or attempting to create an attribute with the same name as a member is not allowed.
+member = RGBa.RED
+print( f"{member.name} {member.value}" )
+RED 1
+\end{python}
+
 
 \subsection{Ensuring unique enumeration values}
@@ -1207,9 +1145,9 @@
 >>> list(Shape)
 [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
->>> list(Weekday)
-[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>,
-<Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
-\end{python}
-Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Weekday.WEEKEND@ aren't shown.
+>>> list(Week)
+[<Week.MONDAY: 1>, <Week.TUESDAY: 2>, <Week.WEDNESDAY: 4>, <Week.THURSDAY: 8>,
+<Week.FRIDAY: 16>, <Week.SATURDAY: 32>, <Week.SUNDAY: 64>]
+\end{python}
+Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Week.WEEKEND@ aren't shown.
 
 The special attribute @__members__@ is a read-only ordered mapping of names to members.
@@ -2212,5 +2150,4 @@
 
 \section{OCaml}
-\lstnewenvironment{ocaml}[1][]{\lstset{language=OCaml,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 % https://ocaml.org/docs/basic-data-types#enumerated-data-types
@@ -2218,9 +2155,8 @@
 
 OCaml provides a variant (union) type, where multiple heterogeneously-typed objects share the same storage.
-The simplest form of the variant type is a list of nullary datatype constructors, which is like an unscoped, pure enumeration.
-
-(I think the value of a ocaml variants are types not object, so I am not sure about this line)
+The simplest form of the variant type is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
+
 OCaml provides a variant (union) type, which is an aggregation of heterogeneous types.
-A basic variant is a list of nullary datatype constructors, which is like an unscoped, pure enumeration. 
+A basic variant is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
 \begin{ocaml}
 type weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun
@@ -2246,5 +2182,5 @@
 type colour = Red | Green of @string@ | Blue of @int * float@
 \end{ocaml}
-A variant with parameter is stored in a memory block, prefixed by an int tag and has its parameters stores as words in the block. 
+A variant with parameter is stored in a memory block, prefixed by an int tag and has its parameters stores as words in the block.
 @colour@ is a summation of a nullary type, a unary product type of @string@, and a cross product of @int@ and @float@.
 (Mathematically, a @Blue@ value is a Cartesian product of the types @int@ type and @float@.)
@@ -2259,5 +2195,4 @@
 @Red, abc, 1 1.5@
 \end{ocaml}
-
 
 A variant type can have a recursive definition.
@@ -2280,5 +2215,5 @@
 
 In summary, an OCaml variant is a singleton value rather than a set of possibly ordered values, and hence, has no notion of enumerabilty.
-Therefore it is not an enumeration, except for the simple pure (nullary) case.
+Therefore it is not an enumeration, except for the simple opaque (nullary) case.
 
 \begin{comment}
@@ -2466,4 +2401,32 @@
 With valediction,
   - Gregor Richards
+
+
+Date: Tue, 16 Apr 2024 11:04:51 -0400
+Subject: Re: C unnamed enumeration
+To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
+CC: <ajbeach@uwaterloo.ca>, <j82liang@uwaterloo.ca>, <mlbrooks@uwaterloo.ca>,
+        <f37yu@uwaterloo.ca>
+From: Gregor Richards <gregor.richards@uwaterloo.ca>
+
+On 4/16/24 09:55, Peter A. Buhr wrote:
+> So what is a variant? Is it a set of tag names, which might be a union or is it
+> a union, which might have tag names?
+
+Your tagless variant bears no resemblance to variants in any functional
+programming language. A variant is a tag AND a union. You might not need to put
+anything in the union, in which case it's a pointless union, but the named tag
+is absolutely mandatory. That's the thing that varies.
+
+I was unaware of std::variant. As far as functional languages are concerned,
+std::variant IS NOT A VARIANT. Perhaps it would be best to use the term ADT for
+the functional language concept, because that term has no other meanings.
+
+An ADT cannot not have a named tag. That's meaningless. The tag is the data
+constructor, which is the thing you actually define when you define an ADT. It
+is strictly the union that's optional.
+
+With valediction,
+  - Gregor Richards
 \end{comment}
 
@@ -2487,5 +2450,5 @@
 \hline
 \hline
-pure			&		&		&		&		&		&		&		&	  	&		&		&		&		& \CM	\\
+opaque			&		&		&		&		&		&		&		&	  	&		&		&		&		& \CM	\\
 \hline
 typed			&		&		&		&		&		&		&		&	  	&		&		& @int@	& integral	& @T@	\\
Index: doc/theses/jiada_liang_MMath/uw-ethesis.bib
===================================================================
--- doc/theses/jiada_liang_MMath/uw-ethesis.bib	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/theses/jiada_liang_MMath/uw-ethesis.bib	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -2,2 +2,12 @@
 % For use with BibTeX
 
+Oxford English Dictionary, s.v. ``enumerate (v.), sense 3,'' September 2023, https://doi.org/10.1093/OED/1113960777. 
+@misc{OEDenumerate,
+    keywords	= {enumerate},
+    key		= {enumerate},
+    title	= {enumerate (v.), sense 3},
+    author	= {Oxford English Dictionary},
+    howpublished= {\url{https://doi.org/10.1093/OED/1113960777}},
+    month	= sep,
+    year	= 2023,
+}
Index: doc/theses/jiada_liang_MMath/uw-ethesis.tex
===================================================================
--- doc/theses/jiada_liang_MMath/uw-ethesis.tex	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/theses/jiada_liang_MMath/uw-ethesis.tex	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -95,4 +95,20 @@
 \CFAStyle						% CFA code-style
 \lstset{language=cfa,belowskip=-1pt} % set default language to CFA
+\lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
+\lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+\lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+\lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+\lstnewenvironment{clang}[1][]{\lstset{language=[ANSI]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+\lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+\lstnewenvironment{haskell}[1][]{\lstset{language=Haskell,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+\lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
+	escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
+\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+\lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+\lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+\lstnewenvironment{ocaml}[1][]{\lstset{language=OCaml,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+
+\newsavebox{\myboxA}
+\newsavebox{\myboxB}
 
 \newcommand{\newtermFont}{\emph}
Index: doc/uC++toCFA/Makefile
===================================================================
--- doc/uC++toCFA/Makefile	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/uC++toCFA/Makefile	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -56,6 +56,6 @@
 	dvips ${Build}/$< -o $@
 
-${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \
-		${Macros}/common.sty ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
+${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${Macros}/common.tex ${Macros}/common.sty \
+		${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
 	# Conditionally create an empty *.ind (index) file for inclusion until makeindex is run.
 	if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi
Index: doc/uC++toCFA/uC++toCFA.tex
===================================================================
--- doc/uC++toCFA/uC++toCFA.tex	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/uC++toCFA/uC++toCFA.tex	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -11,6 +11,6 @@
 %% Created On       : Wed Apr  6 14:53:29 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Thu Jan 11 14:46:14 2024
-%% Update Count     : 5942
+%% Last Modified On : Sat Apr 13 11:11:39 2024
+%% Update Count     : 5969
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -141,19 +141,18 @@
 \CFA uses parametric polymorphism and allows overloading of variables and routines:
 \begin{cfa}
-int i;  char i;  double i;		// overload name i
+int i;  char i;  double i;	$\C[2in]{// overload name i}$
 int i();  double i();  char i();
-i += 1;			$\C[1.5in]{// int i}$
-i += 1.0;		$\C{// double i}$
-i += 'a'; 		$\C{// char i}$
-int j = i();	$\C{// int i()}$
-double j = i();	$\C{// double i();}$
-char j = i();	$\C{// char i()}\CRT$
+i += 1;						$\C{// int i}$
+i += 1.0;					$\C{// double i}$
+i += 'a'; 					$\C{// char i}$
+int j = i();				$\C{// int i()}$
+double j = i();				$\C{// double i();}$
+char j = i();				$\C{// char i()}\CRT$
 \end{cfa}
 \CFA has rebindable references.
-
-\begin{cquote}
-\begin{tabular}{l|l}
-\multicolumn{2}{l}{\lstinline{	int x = 1, y = 2, * p1x = &x, * p1y = &y, ** p2i = &p1x,}} \\
-\multicolumn{2}{l}{\lstinline{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ && r1x = x, & r1y = y, && r2i = r1x;}} \\
+\begin{cquote}
+\begin{tabular}{@{}l|l@{}}
+\multicolumn{2}{@{}l}{\lstinline{	int x = 1, y = 2, * p1x = &x, * p1y = &y, ** p2i = &p1x,}} \\
+\multicolumn{2}{@{}l}{\lstinline{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ && r1x = x, & r1y = y, && r2i = r1x;}} \\
 \begin{uC++}
 **p2i = 3;
@@ -201,7 +200,6 @@
 
 \CFA output streams automatically separate values and insert a newline at the end of the print.
-
-\begin{cquote}
-\begin{tabular}{l|l}
+\begin{cquote}
+\begin{tabular}{@{}l|l@{}}
 \begin{uC++}
 #include <@iostream@>
@@ -226,5 +224,5 @@
 
 \begin{cquote}
-\begin{tabular}{l|l}
+\begin{tabular}{@{}l|l@{}}
 \begin{uC++}
 for ( @;;@ ) { ... }  /  while ( @true@ ) { ... }
@@ -280,5 +278,5 @@
 Currently, \CFA uses macros @ExceptionDecl@ and @ExceptionInst@ to declare and instantiate an exception.
 \begin{cquote}
-\begin{tabular}{l|ll}
+\begin{tabular}{@{}l|ll@{}}
 \begin{uC++}
 
@@ -321,5 +319,5 @@
 
 \begin{cquote}
-\begin{tabular}{l|ll}
+\begin{tabular}{@{}l|ll@{}}
 \begin{uC++}
 
@@ -360,5 +358,5 @@
 
 \begin{cquote}
-\begin{tabular}{l|l}
+\begin{tabular}{@{}l|l@{}}
 \begin{uC++}
 struct S {
@@ -383,6 +381,6 @@
 
 \begin{cquote}
-\begin{tabular}{l|l}
-\multicolumn{2}{l}{\lstinline{string s1, s2;}} \\
+\begin{tabular}{@{}l|l@{}}
+\multicolumn{2}{@{}l@{}}{\lstinline{string s1, s2;}} \\
 \begin{uC++}
 s1 = "hi";
@@ -425,5 +423,5 @@
 
 \begin{cquote}
-\begin{tabular}{l|l}
+\begin{tabular}{@{}l|l@{}}
 \begin{uC++}
 struct S {
@@ -456,5 +454,5 @@
 
 \begin{cquote}
-\begin{tabular}{l|l}
+\begin{tabular}{@{}l|l@{}}
 \begin{uC++}
 
@@ -493,5 +491,5 @@
 
 \begin{cquote}
-\begin{tabular}{l|ll}
+\begin{tabular}{@{}l|ll@{}}
 \begin{uC++}
 
@@ -532,5 +530,5 @@
 
 \begin{cquote}
-\begin{tabular}{l|ll}
+\begin{tabular}{@{}l|ll@{}}
 \begin{uC++}
 
@@ -567,5 +565,5 @@
 
 \begin{cquote}
-\begin{tabular}{l|ll}
+\begin{tabular}{@{}l|ll@{}}
 \begin{uC++}
 
@@ -604,5 +602,5 @@
 
 \begin{cquote}
-\begin{tabular}{l|ll}
+\begin{tabular}{@{}l|ll@{}}
 \begin{uC++}
 
Index: doc/user/Makefile
===================================================================
--- doc/user/Makefile	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/user/Makefile	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -60,6 +60,6 @@
 	dvips ${Build}/$< -o $@
 
-${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \
-		${Macros}/common.sty ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
+${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${Macros}/common.tex ${Macros}/common.sty \
+		${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
 	# Conditionally create an empty *.ind (index) file for inclusion until makeindex is run.
 	if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi
@@ -73,5 +73,5 @@
 	makeindex -s ${Macros}/indexstyle ${Build}/${basename $@}.idx
 	# Run again to finish citations
-	${LaTeX} ${basename $@}.tex
+#	${LaTeX} ${basename $@}.tex
 	# Run again to get index title into table of contents
 #	${LaTeX} ${basename $@}.tex
Index: doc/user/user.tex
===================================================================
--- doc/user/user.tex	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ doc/user/user.tex	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -11,6 +11,6 @@
 %% Created On       : Wed Apr  6 14:53:29 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Mon Feb 12 11:50:26 2024
-%% Update Count     : 6199
+%% Last Modified On : Tue Apr 23 14:13:10 2024
+%% Update Count     : 6623
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -69,5 +69,5 @@
 \lstset{language=CFA}									% CFA default lnaguage
 \lstnewenvironment{C++}[1][]                            % use C++ style
-{\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®},#1}}
+{\lstset{language=C++,escapechar=§,moredelim=**[is][\protect\color{red}]{®}{®},#1}}
 {}
 
@@ -130,5 +130,5 @@
 \vspace*{\fill}
 \noindent
-\copyright\,2016, 2018, 2021 \CFA Project \\ \\
+\copyright\,2016, 2018, 2021, 2024 \CFA Project \\ \\
 \noindent
 This work is licensed under the Creative Commons Attribution 4.0 International License.
@@ -312,5 +312,5 @@
 For example, it is possible to write a type-safe \CFA wrapper ©malloc© based on the C ©malloc©:
 \begin{cfa}
-forall( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); }
+forall( T & | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); }
 int * ip = malloc(); §\C{// select type and size from left-hand side}§
 double * dp = malloc();
@@ -1023,47 +1023,47 @@
 while () { sout | "empty"; break; }
 do { sout | "empty"; break; } while ();
-for () { sout | "empty"; break; }							§\C{sout | nl | nlOff;}§
-
-for ( 0 ) { sout | "A"; } sout | "zero";					§\C{sout | nl;}§
-for ( 1 ) { sout | "A"; }									§\C{sout | nl;}§
-for ( 10 ) { sout | "A"; }									§\C{sout | nl;}§
-for ( ~= 10 ) { sout | "A"; }								§\C{sout | nl;}§
-for ( 1 ~= 10 ~ 2 ) { sout | "B"; }							§\C{sout | nl;}§
-for ( 1 -~= 10 ~ 2 ) { sout | "C"; }						§\C{sout | nl;}§
-for ( 0.5 ~ 5.5 ) { sout | "D"; }							§\C{sout | nl;}§
-for ( 0.5 -~ 5.5 ) { sout | "E"; }							§\C{sout | nl;}§
-for ( i; 10 ) { sout | i; }									§\C{sout | nl;}§
-for ( i; ~= 10 ) { sout | i; }								§\C{sout | nl;}§
-for ( i; 1 ~= 10 ~ 2 ) { sout | i; }						§\C{sout | nl;}§
-for ( i; 1 -~= 10 ~ 2 ) { sout | i; }						§\C{sout | nl;}§
-for ( i; 0.5 ~ 5.5 ) { sout | i; }							§\C{sout | nl;}§
-for ( i; 0.5 -~ 5.5 ) { sout | i; }							§\C{sout | nl;}§
-for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }					§\C{sout | nl;}§
-for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; }					§\C{sout | nl | nl | nl;}§
+for () { sout | "empty"; break; }				§\C[3in]{sout | nl | nlOff;}§
+
+for ( 0 ) { sout | "A"; } sout | "zero";		§\C{sout | nl;}§
+for ( 1 ) { sout | "A"; }						§\C{sout | nl;}§
+for ( 10 ) { sout | "A"; }						§\C{sout | nl;}§
+for ( ~= 10 ) { sout | "A"; }					§\C{sout | nl;}§
+for ( 1 ~= 10 ~ 2 ) { sout | "B"; }				§\C{sout | nl;}§
+for ( 1 -~= 10 ~ 2 ) { sout | "C"; }			§\C{sout | nl;}§
+for ( 0.5 ~ 5.5 ) { sout | "D"; }				§\C{sout | nl;}§
+for ( 0.5 -~ 5.5 ) { sout | "E"; }				§\C{sout | nl;}§
+for ( i; 10 ) { sout | i; }						§\C{sout | nl;}§
+for ( i; ~= 10 ) { sout | i; }					§\C{sout | nl;}§
+for ( i; 1 ~= 10 ~ 2 ) { sout | i; }			§\C{sout | nl;}§
+for ( i; 1 -~= 10 ~ 2 ) { sout | i; }			§\C{sout | nl;}§
+for ( i; 0.5 ~ 5.5 ) { sout | i; }				§\C{sout | nl;}§
+for ( i; 0.5 -~ 5.5 ) { sout | i; }				§\C{sout | nl;}§
+for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }		§\C{sout | nl;}§
+for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; }		§\C{sout | nl | nl | nl;}§
 
 enum { N = 10 };
-for ( N ) { sout | "N"; }									§\C{sout | nl;}§
-for ( i; N ) { sout | i; }									§\C{sout | nl;}§
-for ( i; -~ N ) { sout | i; }								§\C{sout | nl | nl | nl;}§
+for ( N ) { sout | "N"; }						§\C{sout | nl;}§
+for ( i; N ) { sout | i; }						§\C{sout | nl;}§
+for ( i; -~ N ) { sout | i; }					§\C{sout | nl | nl | nl;}§
 
 const int low = 3, high = 10, inc = 2;
-for ( i; low ~ high ~ inc + 1 ) { sout | i; }				§\C{sout | nl;}§
-for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; }			§\C{sout | nl;}§
-for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; }		§\C{sout | nl;}§
-for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; }		§\C{sout | nl;}§
+for ( i; low ~ high ~ inc + 1 ) { sout | i; }	§\C{sout | nl;}§
+for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; } §\C{sout | nl;}§
+for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; } §\C{sout | nl;}§
+for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; } §\C{sout | nl;}§
 for ( i; 2.1 ~ @ ~ @ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; } §\C{sout | nl;}§
 for ( i; @ -~ 10 ~ 2 ) { if ( i < 0 ) break; sout | i; }	§\C{sout | nl;}§
 for ( i; 12.1 ~ @ ~ @ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; } §\C{sout | nl;}§
-for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }					§\C{sout | nl;}§
-for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }					§\C{sout | nl;}§
-for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }				§\C{sout | nl;}§
-for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }				§\C{sout | nl;}§
-for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }					§\C{sout | nl;}§
-for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }					§\C{sout | nl;}§
-for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }				§\C{sout | nl;}§
-for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }				§\C{sout | nl;}§
+for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }		§\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }		§\C{sout | nl;}§
+for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }	§\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }	§\C{sout | nl;}§
+for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }		§\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }		§\C{sout | nl;}§
+for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }	§\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }	§\C{sout | nl;}§
 for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§
 for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§
-for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } §\C{sout | nl;}§
+for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } §\C{sout | nl;}\CRT§
 \end{cfa}
 &
@@ -2960,4 +2960,5 @@
 The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter ©x© of type array of 5 integers.
 Since the strings overlap starting with the open bracket, ©[©, there is an ambiguous interpretation for the string.
+
 As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity:
 \begin{cfa}
@@ -2965,5 +2966,5 @@
 int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§
 \end{cfa}
-The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo.
+The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to ©foo©.
 The redefinition of a type name in a parameter list is the only context in C where the character ©*© can appear to the left of a type name, and \CFA relies on all type qualifier characters appearing to the right of the type name.
 The inability to use \CFA declarations in these two contexts is probably a blessing because it precludes programmers from arbitrarily switching between declarations forms within a declaration contexts.
@@ -3055,4 +3056,160 @@
 static [ int ] g ( int );
 \end{cfa}
+
+
+\subsection{Postfix Function}
+\label{s:PostfixFunction}
+\index{postfix function}
+
+\CFA provides an alternative call syntax where the argument appears before the function name.
+The syntax uses the backquote ©`© to separate the parameters/arguments and function name: ©?`© denotes a postfix-function name, \eg ©int ?`h( int s )© and ©`© denotes a postfix-function call, \eg ©0`h© meaning ©h( 0 )©.
+\begin{cquote}
+\begin{tabular}{@{}l|l|l|l@{}}
+postfix function & constant argument call & variable argument call & postfix function pointer \\
+\hline
+\begin{cfa}
+int ?`h( int s );
+int ?`h( double s );
+int ?`m( char c );
+int ?`m( const char * s );
+int ?`t( int a, int b, int c );
+\end{cfa}
+&	
+\begin{cfa}
+0`h;
+3.5`h;
+'1'`m;
+"123" "456"`m;
+[1, 2, 3]`t;
+\end{cfa}
+&	
+\begin{cfa}
+int i = 7;
+i`h;
+(i + 3)`h;
+(i + 3.5)`h;
+\end{cfa}
+&	
+\begin{cfa}
+int (* ?`p)( int i );
+?`p = ?`h;
+3`p;
+i`p;
+(i + 3)`p;
+\end{cfa}
+\end{tabular}
+\end{cquote}
+Note, to pass \emph{multiple} arguments to a postfix function requires a \Index{tuple}, \eg ©[1, 2, 3]`t©, which forms a single argument that is flattened into the multiple arguments \see{\VRef{s:Tuple}}.
+Similarly, if the argument is an expression, it must be parenthesized, \eg ©(i + 3)`h©, or only the last operand of the expression is the argument, \eg ©i + (3`h)©.
+
+\VRef[Figure]{f:UnitsComparison} shows a common usage for postfix functions: converting basic literals into user literals.
+\see*{\VRef{s:DynamicStorageManagement} for other uses for postfix functions.}
+The \CFA example (left) stores a mass in units of stones (1 stone = 14 lb or 6.35 kg) and provides an addition operator (imagine a full set of arithmetic operators).
+The three postfixing function names ©st©, ©lb©, and ©kg©, represent units stones, pounds, and kilograms, respectively.
+Each name has two forms that bidirectional convert: a value of a specified unit to stones, \eg ©w = 14`lb© $\Rightarrow$ ©w == 1© stone or a ©Weight© from stones back to specific units, \eg ©w`lb© (1 stone) to ©14©.
+All arithmetic operations manipulate stones and the postfix operations convert to the different units.
+A similar group of postfix functions provide user constants for converting time units into nanoseconds, which is the basic time unit, \eg ©ns©, ©us©, ©ms©, ©s©, ©m©, ©h©, ©d©, and ©w©, for nanosecond, microsecond, millisecond, second, minute, hour, day, and week, respectively.
+(Note, month is not a fixed period of time nor is year because of leap years.)
+
+\begin{figure}
+\centering
+\begin{tabular}{@{}l|l@{}}
+\multicolumn{1}{@{}c|}{\textbf{\CFA Postfix Routine}} & \multicolumn{1}{c@{}}{\textbf{\CC User Literals}} \\
+\hline
+\begin{cfa}
+struct Weight {
+	double stones;
+};
+
+
+Weight ?+?( Weight l, Weight r ) {
+	return l.stones + r.stones;
+}
+Weight ®?`st®( double w ) { return w; }
+double ®?`st®( Weight w ) { return w.stones; }
+Weight ®?`lb®( double w ) { return w / 14.0; }
+double ®?`lb®( Weight w ) { return w.stones * 14.0; }
+Weight ®?`kg®( double w ) { return w / 6.35; }
+double ®?`kg®( Weight w ) { return w.stones * 6.35; }
+int main() {
+	Weight w, heavy = { 20 }; // stones
+	w = 155®`lb®;
+	w = 0b_1111®`st®;
+	w = 0_233®`lb®;
+	w = 0x_9b®`kg®;
+	w = 5.5®`st® + 8®`kg® + 25.01®`lb® + heavy;
+}
+\end{cfa}
+&
+\begin{C++}
+struct Weight {
+	double stones;
+	Weight() {}
+	Weight( double w ) { stones = w; }
+};
+Weight operator+( Weight l, Weight r ) {
+	return l.stones + r.stones;
+}
+Weight operator®""_st®( long double w ) { return w; }
+Weight operator®""_lb®( long double w ) { return w / 14.0; }
+Weight operator®""_kg®( long double w ) { return w / 6.35; }
+Weight operator®""_st®( unsigned long long int w ) { return w; }
+Weight operator®""_lb®( unsigned long long int w ) { return w / 14.0; }
+Weight operator®""_kg®( unsigned long long int w ) { return w / 6.35; }
+int main() {
+	Weight w, heavy = { 20 }; // stones
+	w = 155®_lb®;
+	w = 0b1111®_st®;
+	w = 0'233®_lb®;		// quote separator
+	w = 0x9b®_kg®;
+	w = 5.5®_st® + 8®_kg® + 25.01®_lb® + heavy;
+}
+\end{C++}
+\end{tabular}
+
+\begin{comment}
+Time : comparison of time units. \\
+\begin{tabular}{@{}ll@{}}
+\CFA & \CC \\
+\begin{cfa}
+#include <fstream.hfa>
+#include <time.hfa>
+
+
+Duration s = 1`h + 2 * 10`m + 70`s / 10;
+sout | "1 hour + 2*10 min + 70/10 sec = " | s | "seconds";
+sout | "Dividing that by 2 minutes gives" | s / 2`m;
+sout | "Dividing that by 2 gives" | s / 2 | "seconds\n";
+sout | s | "seconds is"
+	  | s`h | "hours,"
+	  | (s % 1`h)`m | "minutes,"
+	  | (s % 1`m)`s | "seconds";
+\end{cfa}
+&	
+\begin{C++}
+#include <iostream>
+#include <chrono>
+using namespace std;
+using namespace std::chrono;
+seconds s = hours(1) + 2 * minutes(10) + seconds(70) / 10;
+cout << "1 hour + 2*10 min + 70/10 sec = " << s.count() << " seconds\n";
+cout << "Dividing that by 2 minutes gives " << s / minutes(2) << '\n';
+cout << "Dividing that by 2 gives " << (s / 2).count() << " seconds\n";
+cout << s.count() << " seconds is "
+	  << duration_cast<hours>( s ).count() << " hours, "
+	  << duration_cast<minutes>( s % hours(1) ).count() << " minutes, "
+	  << duration_cast<seconds>( s % minutes(1) ).count() << " seconds\n";
+\end{C++}
+\end{tabular}
+\end{comment}
+
+\caption{Units: Stone, Pound, Kilogram Comparison}
+\label{f:UnitsComparison}
+\end{figure}
+
+The \CC example (right) provides a \emph{restricted} capability via user literals.
+The \lstinline[language=C++]{operator ""} only takes a constant argument (\ie no variable argument), and the constant type must be the highest-level constant-type, \eg ©long double© for all floating-point constants.
+As well, there is no constant conversion, \ie ©int© to ©double© constants, so integral constants are handled by a separate set of routines, with maximal integral type ©unsigned long long int©.
+Finally, there is no mechanism to use this syntax for a bidirectional conversion because \lstinline[language=C++]{operator ""} does not accept variable arguments.
 
 
@@ -3389,4 +3546,5 @@
 
 \section{Tuple}
+\label{s:Tuple}
 
 In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call.
@@ -3809,8 +3967,8 @@
 \subsection{Polymorphism}
 
-Due to the implicit flattening and structuring conversions involved in argument passing, ©otype© and ©dtype© parameters are restricted to matching only with non-tuple types.
+Due to the implicit flattening and structuring conversions involved in argument passing, object and opaque parameters are restricted to matching only with non-tuple types.
 The integration of polymorphism, type assertions, and monomorphic specialization of tuple-assertions are a primary contribution of this thesis to the design of tuples.
 \begin{cfa}
-forall(T, dtype U)
+forall(T, U &)
 void f(T x, U * y);
 
@@ -4047,6 +4205,5 @@
 [ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = §\emph{expr}§;
 \end{cfa}
-\index{lvalue}
-The left-hand side is a tuple of \LstBasicStyle{\emph{lvalues}}, which is a list of expressions each yielding an address, \ie any data object that can appear on the left-hand side of a conventional assignment statement.
+The left-hand side is a tuple of \LstBasicStyle{\emph{\Index{lvalue}}}s, which is a list of expressions each yielding an address, \ie any data object that can appear on the left-hand side of a conventional assignment statement.
 \LstBasicStyle{\emph{expr}} is any standard arithmetic expression.
 Clearly, the types of the entities being assigned must be type compatible with the value of the expression.
@@ -4086,9 +4243,8 @@
 Multiple assignment has the following form:
 \begin{cfa}
-[ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = [ §\emph{expr}§, ... , §\emph{expr}§ ];
-\end{cfa}
-\index{lvalue}
-The left-hand side is a tuple of \emph{lvalues}, and the right-hand side is a tuple of \emph{expr}s.
-Each \emph{expr} appearing on the right-hand side of a multiple assignment statement is assigned to the corresponding \emph{lvalues} on the left-hand side of the statement using parallel semantics for each assignment.
+[ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = [ §\emph{expr}§, ... , §\emph{expr}§ ];§
+\end{cfa}
+The left-hand side is a tuple of \LstBasicStyle{\emph{\Index{lvalue}}}s, and the right-hand side is a tuple of \LstBasicStyle{\emph{expr}}s.
+Each \LstBasicStyle{\emph{expr}} appearing on the right-hand side of a multiple assignment statement is assigned to the corresponding \LstBasicStyle{\emph{lvalues}} on the left-hand side of the statement using parallel semantics for each assignment.
 An example of multiple assignment is:
 \begin{cfa}
@@ -4925,8 +5081,8 @@
 	sout | '1' | '2' | '3';
 	sout | 1 | "" | 2 | "" | 3;
-	sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x Â£" | 6 | "x Â¥"
-		| 7 | "x Â¡" | 8 | "x Â¿" | 9 | "x Â«" | 10;
+	sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x ¥"
+		| 7 | "x ¡" | 8 | "x ¿" | 9 | "x «" | 10;
 	sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x"
-		| 7 | "Â¢ x" | 8 | "Â» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
+		| 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
 	sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx";
 	sout | "x ( " | 1 | " ) x" | 2 | " , x" | 3 | " :x: " | 4;
@@ -7775,5 +7931,5 @@
 \item[Rationale:] increase type safety
 \item[Effect on original feature:] deletion of semantically well-defined feature.
-\item[Difficulty of converting:] requires adding a cast \see{\VRef{s:StorageManagement} for better alternatives}:
+\item[Difficulty of converting:] requires adding a cast \see{\VRef{s:DynamicStorageManagement} for better alternatives}:
 \begin{cfa}
 	int * b = (int *)malloc( sizeof(int) );
@@ -7987,173 +8143,385 @@
 \section{Standard Library}
 \label{s:StandardLibrary}
-
-The \CFA standard-library wraps explicitly-polymorphic C routines into implicitly-polymorphic versions.
-
-
-\subsection{Storage Management}
-\label{s:StorageManagement}
-
-The storage-management routines extend their C equivalents by overloading, alternate names, providing shallow type-safety, and removing the need to specify the allocation size for non-array types.
-
-C storage management provides the following capabilities:
-\begin{description}
-\item[filled]
-after allocation with a specified character or value.
+\index{standard library}
+
+The \CFA standard-library extends existing C library routines by adding new function, wrapping existing explicitly-polymorphic C routines into implicitly-polymorphic versions, and adding new \CFA extensions.
+
+
+\subsection{Dynamic Storage-Management}
+\label{s:DynamicStorageManagement}
+\index{dynamic storage-management}\index{storage management}
+
+Dynamic storage-management in C is based on explicit allocation and deallocation (©malloc©/©free©).
+Programmer's must manage all allocated storage via its address (pointer) and subsequently deallocate the storage via this address.
+Storage that is not deallocated becomes inaccessible, called a \newterm{memory leak}, which can only be detected at program termination.
+Storage freed twice is an error, called a \newterm{duplicate free}, which can sometimes be detected.
+Storage used after it is deallocated is an error, called using a \newterm{dangling pointer}, which can sometimes be detected.
+
+
+\subsubsection{C Interface}
+
+C dynamic storage-management provides the following properties.
+\begin{description}[leftmargin=*]
+\item[fill]
+storage after an allocation with a specified character or value.
+\item[align]
+an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
+\item[scale]
+an allocation size to the specified number of array elements.
+An array may be filled, resized, or aligned.
 \item[resize]
 an existing allocation to decreased or increased its size.
-In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied into the new allocation.
-For an increase in storage size, new storage after the copied data may be filled.
-\item[align]
-an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
-\item[array]
-the allocation size is scaled to the specified number of array elements.
-An array may be filled, resized, or aligned.
+In either direction, new storage may or may not be allocated, but if there is a new allocation, as much data from the existing allocation is copied into the new allocation.
+When new storage is allocated, it may be aligned and storage after copied data may be filled.
 \end{description}
-\VRef[Table]{t:AllocationVersusCapabilities} shows allocation routines supporting different combinations of storage-management capabilities.
+\VRef[Table]{t:AllocationVersusProperties} shows different combinations of storage-management properties provided by the C and \CFA allocation routines.
+
 \begin{table}
+\caption{Allocation Routines versus Storage-Management Properties}
+\label{t:AllocationVersusProperties}
 \centering
 \begin{minipage}{0.75\textwidth}
 \begin{tabular}{@{}r|l|l|l|l|l@{}}
-\multicolumn{1}{c}{}&		& \multicolumn{1}{c|}{fill}	& resize	& alignment	& array	\\
+		& \multicolumn{1}{c|}{routine} & \multicolumn{1}{c|}{\textbf{fill}} & \textbf{alignment}	& \textbf{scale}	& \textbf{resize} \\
 \hline
 C		& ©malloc©			& no			& no		& no		& no	\\
-		& ©calloc©			& yes (0 only)	& no		& no		& yes	\\
-		& ©realloc©			& copy			& yes		& no		& no	\\
-		& ©memalign©		& no			& no		& yes		& no	\\
-		& ©aligned_alloc©\footnote{Same as ©memalign© but size is an integral multiple of alignment, which is universally ignored.}
-							& no			& no		& yes		& no	\\
-		& ©posix_memalign©	& no			& no		& yes		& no	\\
-		& ©valloc©			& no			& no		& yes (page size)& no	\\
+		& ©calloc©			& yes (0 only)	& no		& yes		& no	\\
+		& ©realloc©			& copy			& no		& no		& yes	\\
+		& ©reallocarray©	& copy			& no		& yes		& yes	\\
+		& ©memalign©		& no			& yes		& no		& no	\\
+		& ©aligned_alloc©\footnote{Same as ©memalign© but size is an integral multiple of alignment.}
+							& no			& yes		& no		& no	\\
+		& ©posix_memalign©	& no			& yes		& no		& no	\\
+		& ©valloc©			& no			& yes (page size)& no	& no	\\
 		& ©pvalloc©\footnote{Same as ©valloc© but rounds size to multiple of page size.}
-							& no			& no		& yes (page size)& no	\\
-\hline
-\CFA	& ©cmemalign©		& yes (0 only)	& no		& yes		& yes	\\
-		& ©realloc©			& copy			& yes		& yes		& no	\\
-		& ©alloc©			& no			& yes		& no		& yes	\\
-		& ©alloc_set©		& yes			& yes		& no		& yes	\\
-		& ©alloc_align©		& no			& yes		& yes		& yes	\\
-		& ©alloc_align_set©	& yes			& yes		& yes		& yes	\\
+							& no			& yes (page size)& no	& no	\\
+\hline																        
+\CFA	& ©cmemalign©		& yes (0 only)	& yes		& yes		& no	\\
+		& ©resize©			& no copy		& yes		& no		& yes	\\
+		& ©realloc©			& copy			& yes		& no		& yes	\\
+		& ©alloc©\footnote{Multiple overloads with different parameters.}
+							& yes			& yes		& yes		& yes
 \end{tabular}
 \end{minipage}
-\caption{Allocation Routines versus Storage-Management Capabilities}
-\label{t:AllocationVersusCapabilities}
+\vspace*{-10pt}
 \end{table}
 
-\CFA memory management extends the type safety of all allocations by using the type of the left-hand-side type to determine the allocation size and return a matching type for the new storage.
-Type-safe allocation is provided for all C allocation routines and new \CFA allocation routines, \eg in
-\begin{cfa}
-int * ip = (int *)malloc( sizeof(int) ); §\C{// C}§
-int * ip = malloc();					§\C{// \CFA type-safe version of C malloc}§
-int * ip = alloc();						§\C{// \CFA type-safe uniform alloc}§
-\end{cfa}
-the latter two allocations determine the allocation size from the type of ©p© (©int©) and cast the pointer to the allocated storage to ©int *©.
-
-\CFA memory management extends allocation safety by implicitly honouring all alignment requirements, \eg in
-\begin{cfa}
-struct S { int i; } __attribute__(( aligned( 128 ) )); // cache-line alignment
-S * sp = malloc();						§\C{// honour type alignment}§
-\end{cfa}
-the storage allocation is implicitly aligned to 128 rather than the default 16.
-The alignment check is performed at compile time so there is no runtime cost.
-
-\CFA memory management extends the resize capability with the notion of \newterm{sticky properties}.
-Hence, initial allocation capabilities are remembered and maintained when resize requires copying.
-For example, an initial alignment and fill capability are preserved during a resize copy so the copy has the same alignment and extended storage is filled.
-Without sticky properties it is dangerous to use ©realloc©, resulting in an idiom of manually performing the reallocation to maintain correctness.
-\begin{cfa}
-
-\end{cfa}
-
-\CFA memory management extends allocation to support constructors for initialization of allocated storage, \eg in
-\begin{cfa}
-struct S { int i; };					§\C{// cache-line alignment}§
-void ?{}( S & s, int i ) { s.i = i; }
-// assume ?|? operator for printing an S
-
-S & sp = *®new®( 3 );					§\C{// call constructor after allocation}§
-sout | sp.i;
-®delete®( &sp );
-
-S * spa = ®anew®( 10, 5 );				§\C{// allocate array and initialize each array element}§
-for ( i; 10 ) sout | spa[i] | nonl;
-sout | nl;
-®adelete®( 10, spa );
+
+\subsubsection{\CFA Interface}
+
+\CFA dynamic memory management:
+\begin{enumerate}[leftmargin=\parindent]
+\item
+extends type safety of all allocation routines by using the left-hand assignment type to determine the allocation size and alignment, and return a matching type for the new storage, which removes many common allocation errors.
+\begin{cfa}
+int * ip = (int *)malloc( sizeof(int) ); §\C[2.3in]{// C}§
+int * ip = malloc();					§\C{// \CFA type-safe call of C malloc}§
+int * ip = calloc();					§\C{// \CFA type-safe call of C calloc}§
+struct __attribute__(( aligned(128) )) spinlock { ... }; // cache alignment
+spinlock * slp = malloc();				§\C{// correct size, alignment, and return type}\CRT§
+\end{cfa}
+Here, the alignment of the ©ip© storage is 16 (default) and 128 for ©slp©.
+
+\item
+introduces the notion of \newterm{sticky properties} used in resizing.
+All initial allocation properties are remembered and maintained for use should resize require new storage.
+For example, the initial alignment and fill properties in the initial allocation
+\begin{cfa}
+struct __attribute__(( aligned(4096) )) S { ... };
+S * sp = calloc( 10 );					§\C{// align 4K and zero fill}§
+sp = reallocarray( sp, 100 );			§\C{// preserve 4K alignment and zero fill new storage}§
+\end{cfa}
+are preserved in the resize so the new storage has the same alignment and extra storage after the data copy is zero filled.
+Without sticky properties it is dangerous to resize, resulting in the C idiom of manually performing the reallocation to maintain correctness, which is error prone.
+
+\item
+provides resizing without data copying, which is useful to repurpose an existing block of storage, rather than freeing the old storage and performing a new allocation.
+A resize can take advantage of unused storage after the data to preventing a free/reallocation step altogether.
+
+\item
+provides ©free©/©delete© functions that delete a variable number of allocations.
+\begin{cfa}
+int * ip = malloc(), * jp = malloc(), * kp = malloc(); 
+double * xp = malloc(), * yp = malloc(), * zp = malloc(); 
+free( ®ip, jp, kp, xp, yp, zp® );		§\C{// multiple deallocations}§
+\end{cfa}
+
+\item
+supports constructors for initialization of allocated storage and destructors for deallocation (like \CC).
+\begin{cfa}
+struct S { int v; };					§\C{// default constructors}§
+void ^?{}( S & ) { ... }				§\C{// destructor}§
+S & sp = *®new®( 3 );					§\C{// allocate and call constructor}§
+sout | sp.v;
+®delete®( &sp );						§\C{// call destructor}§
+S * spa1 = ®anew®( 10, 5 ), * spa2 = ®anew®( 10, 8 ); §\C{// allocate array and call constructor for each array element}§
+for ( i; 10 ) sout | spa1[i].v | spa2[i].v | nonl; sout | nl;
+®adelete®( spa1, spa2 );				§\C{// call destructors on all array objects}§
+
+3
+5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8
 \end{cfa}
 Allocation routines ©new©/©anew© allocate a variable/array and initialize storage using the allocated type's constructor.
 Note, the matching deallocation routines ©delete©/©adelete©.
-
-\leavevmode
+\CC only supports the default constructor for intializing array elements.
+\begin{C++}
+S * sp = new S[10]®{5}®;				§\C{// disallowed}§
+\end{C++}
+\end{enumerate}
+
+In addition, \CFA provides a new allocator interface to further increase orthogonality and usability of dynamic-memory allocation.
+This interface helps programmers in three ways.
+\begin{enumerate}
+\item
+naming: \CFA regular and ©ttype© polymorphism (similar to \CC variadic templates) is used to encapsulate a wide range of allocation functionality into a single routine name, so programmers do not have to remember multiple routine names for different kinds of dynamic allocations.
+\item
+named arguments: individual allocation properties are specified using postfix function call \see{\VRef{s:PostfixFunction}}, so programmers do not have to remember parameter positions in allocation calls.
+\item
+safe usage: like the \CFA's C-interface, programmers do not have to specify object size or cast allocation results.
+\end{enumerate}
+
+The polymorphic functions
+\begin{cfa}
+T * alloc( ... );
+T * alloc( size_t dim, ... );
+\end{cfa}
+are overloaded with a variable number of allocation properties.
+These allocation properties can be passed as named arguments when calling the \Indexc{alloc} routine.
+A call without parameters returns an uninitialized dynamically allocated object of type ©T© (\Indexc{malloc}).
+A call with only the dimension (dim) parameter returns an uninitialized dynamically allocated array of objects with type ©T© (\Indexc{aalloc}).
+The variable number of arguments consist of allocation properties to specialize the allocation.
+The properties ©resize© and ©realloc© are associated with an existing allocation variable indicating how its storage is modified.
+
+The following allocation property functions may be combined and appear in any order as arguments to ©alloc©,
+\begin{itemize}
+\item
+©T_align ?`align( size_t alignment )© to align an allocation.
+The alignment parameter must be $\ge$ the default alignment (©libAlign()© in \CFA) and a power of two, \eg the following return a dynamic object and object array aligned on a 256 and 4096-byte boundary.
+\begin{cfa}
+int * i0 = alloc( ®256`align® );  sout | i0 | nl;
+int * i1 = alloc( 3, ®4096`align® );  for (i; 3 ) sout | &i1[i] | nonl;  sout | nl;
+free( i0, i1 );
+
+0x5555565699®00®  // 256 alignment
+0x55555656c®000® 0x5656c004 0x5656c008  // 4K array alignment
+\end{cfa}
+
+\item
+©T_fill(T) ?`fill( /* various types */ )© to initialize storage.
+There are three ways to fill storage:
+\begin{enumerate}
+\item
+A ©char© fills every byte of each object.
+\item
+An object of the returned type fills each object.
+\item
+An object array pointer fills some or all of the corresponding object array.
+\end{enumerate}
+For example:
+\begin{cfa}[numbers=left]
+int * i0 = alloc( ®0n`fill® );  sout | *i0 | nl;  // 0n disambiguates 0p
+int * i1 = alloc( ®5`fill® );  sout | *i1 | nl;
+int * i2 = alloc( ®'\xfe'`fill® ); sout | hex( *i2 ) | nl;
+int * i3 = alloc( 5, ®5`fill® );  for ( i; 5 ) sout | i3[i] | nonl; sout | nl;
+int * i4 = alloc( 5, ®0xdeadbeefN`fill® );  for ( i; 5 ) sout | hex( i4[i] ) | nonl; sout | nl;
+int * i5 = alloc( 5, ®i3`fill® );  for ( i; 5 ) sout | i5[i] | nonl; sout | nl; // completely fill from i3
+int * i6 = alloc( 5, ®[i3, 3]`fill® );  for ( i; 5 ) sout | i6[i] | nonl; sout | nl; // partial fill from i3
+free( i0, i1, i2, i3, i4, i5, i6 );
+\end{cfa}
+\begin{lstlisting}[numbers=left]
+0
+5
+0xfefefefe
+5 5 5 5 5
+0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
+5 5 5 5 5
+5 5 5 -555819298 -555819298  // two undefined values
+\end{lstlisting}
+Examples 1 to 3 fill an object with a value or characters.
+Examples 4 to 7 fill an array of objects with values, another array, or part of an array.
+
+\item
+©S_resize(T) ?`resize( void * oaddr )© used to resize, realign, and fill, where the old object data is not copied to the new object.
+The old object type may be different from the new object type, since the values are not used.
+For example:
+\begin{cfa}[numbers=left]
+int * ip = alloc( ®5`fill® );  sout | ip | *ip;
+ip = alloc( ®ip`resize®, ®256`align®, ®7`fill® );  sout | ip | *ip;
+double * dp = alloc( ®ip`resize®, ®4096`align®, ®13.5`fill® );  sout | dp | *dp;
+free( dp );  // DO NOT FREE ip AS ITS STORAGE IS MOVED TO dp
+\end{cfa}
+\begin{lstlisting}[numbers=left]
+0x555555580a80 5
+0x555555581100 7
+0x555555587000 13.5
+\end{lstlisting}
+Examples 2 to 3 change the alignment, fill, and size for the initial storage of ©i©.
+
+\begin{cfa}[numbers=left]
+int * ia = alloc( 5, ®5`fill® );  sout | ia | nonl;  for ( i; 5 ) sout | ia[i] | nonl; sout | nl;
+ia = alloc( 10, ®ia`resize®, ®7`fill® );  sout | ia | nonl;  for ( i; 10 ) sout | ia[i] | nonl; sout | nl;
+ia = alloc( 5, ®ia`resize®, ®512`align®, ®13`fill® ); sout | ia | nonl; for ( i; 5 ) sout | ia[i] | nonl; sout | nl;;
+ia = alloc( 3, ®ia`resize®, ®4096`align®, ®2`fill® );  for ( i; 3 ) sout | &ia[i] | ia[i] | nonl; sout | nl;
+free( ia );
+\end{cfa}
+\begin{lstlisting}[numbers=left]
+0x55555656d540 5 5 5 5 5
+0x55555656d480 7 7 7 7 7 7 7 7 7 7
+0x55555656fe00 13 13 13 13 13
+0x555556570000 2 0x555556570004 2 0x555556570008 2
+\end{lstlisting}
+Examples 2 to 4 change the array size, alignment, and fill initializes all storage because no data is copied.
+
+\item
+©S_realloc(T) ?`realloc( T * a ))©
+used to resize, realign, and fill, where the old object data is copied to the new object.
+The old object type must be the same as the new object type, since the value is used.
+Note, for ©fill©, only the extra space after copying the data from the old object is filled with the given parameter.
+For example:
+\begin{cfa}[numbers=left]
+int * ip = alloc( ®5`fill® );  sout | ip | *ip;
+ip = alloc( ®ip`realloc®, ®256`align® );  sout | ip | *ip;
+ip = alloc( ®ip`realloc®, ®4096`align®, ®13`fill® );  sout | ip | *ip;
+free( ip );
+\end{cfa}
+\begin{lstlisting}[numbers=left]
+0x55555556d5c0 5
+0x555555570000 5
+0x555555571000 5
+\end{lstlisting}
+Examples 2 to 3 change the alignment for the initial storage of ©i©.
+The ©13`fill© in example 3 does nothing because no new storage is added.
+
+\begin{cfa}[numbers=left]
+int * ia = alloc( 5, ®5`fill® );  sout | ia | nonl;  for ( i; 5 ) sout | ia[i] | nonl; sout | nl;
+ia = alloc( 10, ®ia`realloc®, ®7`fill® );  sout | ia | nonl;  for ( i; 10 ) sout | ia[i] | nonl; sout | nl;
+ia = alloc( 5, ®ia`realloc®, ®512`align®, ®13`fill® );  sout | ia | nonl; for ( i; 5 ) sout | ia[i] | nonl; sout | nl;;
+ia = alloc( 3, ®ia`realloc®, ®4096`align®, ®2`fill® );  for ( i; 3 ) sout | &ia[i] | ia[i] | nonl; sout | nl;
+free( ia );
+\end{cfa}
+\begin{lstlisting}[numbers=left]
+0x55555656d540 5 5 5 5 5
+0x55555656d480 7 7 7 7 7 7 7 7 7 7
+0x555556570e00 5 5 5 5 5
+0x5555556571000 5 0x555556571004 5 0x555556571008 5
+\end{lstlisting}
+Examples 2 to 4 change the array size, alignment, and fill does no initialization after the copied data, as no new storage is added.
+\end{itemize}
+
+\medskip
 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
 extern "C" {
-	// C unsafe allocation
-	void * malloc( size_t size );§\indexc{malloc}§
-	void * calloc( size_t dim, size_t size );§\indexc{calloc}§
-	void * realloc( void * ptr, size_t size );§\indexc{realloc}§
-	void * memalign( size_t align, size_t size );§\indexc{memalign}§
-	void * aligned_alloc( size_t align, size_t size );§\indexc{aligned_alloc}§
-	int posix_memalign( void ** ptr, size_t align, size_t size );§\indexc{posix_memalign}§
-	void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize );§\indexc{cmemalign}§ // CFA
-
-	// C unsafe initialization/copy
-	void * memset( void * dest, int c, size_t size );§\indexc{memset}§
-	void * memcpy( void * dest, const void * src, size_t size );§\indexc{memcpy}§
-}
-
-void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
-
-forall( dtype T | sized(T) ) {
-	// §\CFA§ safe equivalents, i.e., implicit size specification
-	T * malloc( void );
-	T * calloc( size_t dim );
-	T * realloc( T * ptr, size_t size );
-	T * memalign( size_t align );
-	T * cmemalign( size_t align, size_t dim  );
-	T * aligned_alloc( size_t align );
-	int posix_memalign( T ** ptr, size_t align );
+	// New C allocation operations.
+	void * aalloc( size_t dim, size_t elemSize );§\indexc{aalloc}§
+	void * resize( void * oaddr, size_t size );§\indexc{resize}§
+	void * amemalign( size_t align, size_t dim, size_t elemSize );§\indexc{amemalign}§
+	void * cmemalign( size_t align, size_t dim, size_t elemSize );§\indexc{cmemalign}§
+	size_t malloc_alignment( void * addr );§\indexc{malloc_alignment}§
+	bool malloc_zero_fill( void * addr );§\indexc{malloc_zero_fill}§
+	size_t malloc_size( void * addr );§\indexc{malloc_size}§
+	int malloc_stats_fd( int fd );§\indexc{malloc_stats_fd}§
+	size_t malloc_expansion();§\indexc{malloc_expansion}§ §\C{// heap expansion size (bytes)}§
+	size_t malloc_mmap_start();§\indexc{malloc_mmap_start}§ §\C{// crossover allocation size from sbrk to mmap}§
+	size_t malloc_unfreed();§\indexc{malloc_unfreed()}§	§\C{// heap unfreed size (bytes)}§
+	void malloc_stats_clear();§\indexc{malloc_stats_clear}§	§\C{// clear heap statistics}§
+}
+
+// New allocation operations.
+void * resize( void * oaddr, size_t alignment, size_t size );
+void * realloc( void * oaddr, size_t alignment, size_t size );
+void * reallocarray( void * oaddr, size_t nalign, size_t dim, size_t elemSize );
+
+forall( T & | sized(T) ) {
+	// §\CFA§ safe equivalents, i.e., implicit size specification, eliminate return-type cast
+	T * malloc( void );§\indexc{malloc}§
+	T * aalloc( size_t dim );§\indexc{aalloc}§
+	T * calloc( size_t dim );§\indexc{calloc}§
+	T * resize( T * ptr, size_t size );§\indexc{resize}§
+	T * resize( T * ptr, size_t alignment, size_t size );
+	T * realloc( T * ptr, size_t size );§\indexc{realloc}§
+	T * realloc( T * ptr, size_t alignment, size_t size );
+	T * reallocarray( T * ptr, size_t dim );§\indexc{reallocarray}§
+	T * reallocarray( T * ptr, size_t alignment, size_t dim );
+	T * memalign( size_t align );§\indexc{memalign}§
+	T * amemalign( size_t align, size_t dim );§\indexc{amemalign}§
+	T * cmemalign( size_t align, size_t dim );§\indexc{aalloc}§
+	T * aligned_alloc( size_t align );§\indexc{aligned_alloc}§
+	int posix_memalign( T ** ptr, size_t align );§\indexc{posix_memalign}§
+	T * valloc( void );§\indexc{valloc}§
+	T * pvalloc( void );§\indexc{pvalloc}§
 
 	// §\CFA§ safe general allocation, fill, resize, alignment, array
-	T * alloc( void );§\indexc{alloc}§					§\C[3.5in]{// variable, T size}§
-	T * alloc( size_t dim );							§\C{// array[dim], T size elements}§
-	T * alloc( T ptr[], size_t dim );					§\C{// realloc array[dim], T size elements}§
-
-	T * alloc_set( char fill );§\indexc{alloc_set}§		§\C{// variable, T size, fill bytes with value}§
-	T * alloc_set( T fill );							§\C{// variable, T size, fill with value}§
-	T * alloc_set( size_t dim, char fill );				§\C{// array[dim], T size elements, fill bytes with value}§
-	T * alloc_set( size_t dim, T fill );				§\C{// array[dim], T size elements, fill elements with value}§
-	T * alloc_set( size_t dim, const T fill[] );		§\C{// array[dim], T size elements, fill elements with array}§
-	T * alloc_set( T ptr[], size_t dim, char fill );	§\C{// realloc array[dim], T size elements, fill bytes with value}§
-
-	T * alloc_align( size_t align );					§\C{// aligned variable, T size}§
-	T * alloc_align( size_t align, size_t dim );		§\C{// aligned array[dim], T size elements}§
-	T * alloc_align( T ptr[], size_t align );			§\C{// realloc new aligned array}§
-	T * alloc_align( T ptr[], size_t align, size_t dim ); §\C{// realloc new aligned array[dim]}§
-
-	T * alloc_align_set( size_t align, char fill );		§\C{// aligned variable, T size, fill bytes with value}§
-	T * alloc_align_set( size_t align, T fill );		§\C{// aligned variable, T size, fill with value}§
-	T * alloc_align_set( size_t align, size_t dim, char fill ); §\C{// aligned array[dim], T size elements, fill bytes with value}§
-	T * alloc_align_set( size_t align, size_t dim, T fill ); §\C{// aligned array[dim], T size elements, fill elements with value}§
-	T * alloc_align_set( size_t align, size_t dim, const T fill[] ); §\C{// aligned array[dim], T size elements, fill elements with array}§
-	T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); §\C{// realloc new aligned array[dim], fill new bytes with value}§
-
-	// §\CFA§ safe initialization/copy, i.e., implicit size specification
-	T * memset( T * dest, char fill );§\indexc{memset}§
-	T * memcpy( T * dest, const T * src );§\indexc{memcpy}§
-
-	// §\CFA§ safe initialization/copy, i.e., implicit size specification, array types
-	T * amemset( T dest[], char fill, size_t dim );
+	T * alloc( ... );§\indexc{alloc}§					§\C{// variable, T size}§
+	T * alloc( size_t dim, ... );
+	T_align ?`align( size_t alignment );§\indexc{align}§
+	T_fill(T) ?`fill( /* various types */ );§\indexc{fill}§
+	T_resize ?`resize( void * oaddr );§\indexc{resize}§
+	T_realloc ?`realloc( void * oaddr ));§\indexc{realloc}§
+}
+
+forall( T &, List ... ) void free( T * ptr, ... ) // deallocation list
+
+// §\CFA§ allocation/deallocation and constructor/destructor, non-array types
+forall( T &, Parms ... | { void ?{}( T &, Parms ); } ) T * new( Parms ... );§\indexc{new}§
+forall( T &, List ... | { void ^?{}( T & ); void delete( List ... ); } );§\indexc{delete}§
+// §\CFA§ allocation/deallocation and constructor/destructor, array types
+forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } ) T * anew( size_t dim, Parms ... );§\indexc{anew}§
+forall( T & | sized(T) | { void ^?{}( T & ); }, List ... } ) void adelete( T arr[], List ... );§\indexc{adelete}§
+\end{cfa}
+
+
+\subsection{Memory Set and Copy}
+
+Like safe memory allocation, \CFA provides safe block initialization and copy.
+While objects should be initialized/copied with constructors/assignment, block operations can be very performant.
+In certain cases the compiler generates block copy operations, such as assigning structures ©s = t©, however C arrays cannot be assigned.
+\begin{cquote}
+\begin{cfa}[aboveskip=0pt,belowskip=0pt]
+struct S { int i, j, k; };
+S s, t, *sp = &s, * tp = &t, sa[10], ta[10];
+\end{cfa}
+\noindent
+\begin{tabular}{@{}l|l@{}}
+\multicolumn{1}{@{}c|}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\
+\begin{cfa}[aboveskip=0pt,belowskip=0pt]
+memset( s, '\0' );
+memset( sp, '\0' );
+
+memcpy( s, t );
+memcpy( sp, tp );
+
+amemset( sa, '\0', 10 );
+amemcpy( sa, ta, 10 );
+\end{cfa}
+&
+\begin{cfa}[aboveskip=0pt,belowskip=0pt]
+memset( &s, '\0', sizeof(s) );
+memset( sp, '\0', sizeof(s) );
+
+memcpy( &s, &t, sizeof(s) );
+memcpy( sp, tp, sizeof(s) );
+
+memset( sa, '\0', sizeof(sa) );
+memcpy( sa, ta, sizeof(sa) );
+\end{cfa}
+\end{tabular}
+\end{cquote}
+These operations provide uniformity between reference and pointer, so object dereferencing, '©&©', is unnecessary.
+
+\begin{cfa}
+static inline forall( T & | sized(T) ) {
+	// CFA safe initialization/copy, i.e., implicit size specification, non-array types
+	T * memset( T * dest, char fill );§\indexc{memset}§	§\C{// all combinations of pointer/reference}§
+	T * memset( T & dest, char fill );
+
+	T * memcpy( T * dest, const T * src );§\indexc{memcpy}§	§\C{// all combinations of pointer/reference}§
+	T * memcpy( T & dest, const T & src );
+	T * memcpy( T * dest, const T & src );
+	T * memcpy( T & dest, const T * src );
+
+	// CFA safe initialization/copy, i.e., implicit size specification, array types
+	T * amemset( T dest[], char fill, size_t dim );§\indexc{memcpy}§
 	T * amemcpy( T dest[], const T src[], size_t dim );
 }
-
-// §\CFA§ allocation/deallocation and constructor/destructor, non-array types
-forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );§\indexc{new}§
-forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );§\indexc{delete}§
-forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } )
-  void delete( T * ptr, Params rest );
-
-// §\CFA§ allocation/deallocation and constructor/destructor, array types
-forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
-forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
-forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
-  void adelete( size_t dim, T arr[], Params rest );
 \end{cfa}
 
@@ -9290,6 +9658,6 @@
 Int sqrt( Int oper );
 
-forall( dtype istype | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
-forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
+forall( istype & | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
+forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
 \end{cfa}
 \VRef[Figure]{f:MultiPrecisionFactorials} shows \CFA and C factorial programs using the GMP interfaces.
@@ -9299,6 +9667,20 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
-\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{C}}	& \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{\CFA}}	\\
+\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}}	& \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{C}}	\\
 \hline
+\begin{cfa}
+#include <gmp.hfa>§\indexc{gmp}§
+int main( void ) {
+	sout | "Factorial Numbers";
+	®Int® fact = 1;
+
+	sout | 0 | fact;
+	for ( i; 40 ) {
+		fact *= i;
+		sout | i | fact;
+	}
+}
+\end{cfa}
+&
 \begin{cfa}
 #include <gmp.h>§\indexc{gmp.h}§
@@ -9311,18 +9693,4 @@
 		®mpz_mul_ui®( fact, fact, i );
 		®gmp_printf®( "%d %Zd\n", i, fact );
-	}
-}
-\end{cfa}
-&
-\begin{cfa}
-#include <gmp.hfa>§\indexc{gmp}§
-int main( void ) {
-	sout | "Factorial Numbers";
-	Int fact = 1;
-
-	sout | 0 | fact;
-	for ( i; 40 ) {
-		fact *= i;
-		sout | i | fact;
 	}
 }
@@ -9419,6 +9787,6 @@
 Rational narrow( double f, long int md );
 
-forall( dtype istype | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
-forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
+forall( istype & | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
+forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
 \end{cfa}
 
@@ -9440,4 +9808,22 @@
 \end{document}
 
+From: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>
+To: Peter Buhr <pabuhr@uwaterloo.ca>,
+        Andrew James Beach
+	<ajbeach@uwaterloo.ca>,
+        Fangren Yu <f37yu@uwaterloo.ca>, Jiada Liang
+	<j82liang@uwaterloo.ca>
+Subject: The White House on Memory-Safe programming
+Date: Mon, 4 Mar 2024 16:49:53 +0000
+
+I heard tell of this announcement last night.  Haven't read the actual report yet.
+
+Most mainstream article I can find:  https://me.pcmag.com/en/security/22413/white-house-to-developers-using-c-or-c-invites-cybersecurity-risks
+Less fluffy summary:  https://www.developer-tech.com/news/2024/feb/27/white-house-urges-adoption-memory-safe-programming-languages/
+Horse's Mouth:  https://www.whitehouse.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf
+"This report focuses on the programming language as a primary building block, and explores hardware architecture and formal methods as complementary approaches"
+
+A contrary analysis:  https://hackaday.com/2024/02/29/the-white-house-memory-safety-appeal-is-a-security-red-herring/
+
 % Local Variables: %
 % tab-width: 4 %
Index: libcfa/src/concurrency/actor.hfa
===================================================================
--- libcfa/src/concurrency/actor.hfa	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ libcfa/src/concurrency/actor.hfa	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -299,5 +299,5 @@
 
 	if ( seperate_clus ) {
-		cluster = alloc();
+		this.cluster = alloc();
 		(*cluster){};
 	} else cluster = active_cluster();
@@ -360,5 +360,5 @@
 	adelete( worker_req_queues );
 	adelete( processors );
-	if ( seperate_clus ) delete( cluster );
+	if ( seperate_clus ) delete( this.cluster );
 
 	#ifdef ACTOR_STATS // print formatted stats
Index: libcfa/src/concurrency/kernel/fwd.hfa
===================================================================
--- libcfa/src/concurrency/kernel/fwd.hfa	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ libcfa/src/concurrency/kernel/fwd.hfa	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -374,5 +374,5 @@
 				// since if that is the case, the oneshot was fulfilled (unparking this thread)
 				// and the oneshot should not be needed any more
-				__attribute__((unused)) struct oneshot * was = this.ptr;
+				struct oneshot * was __attribute__((unused)) = this.ptr; // used in option verify
 				/* paranoid */ verifyf( was == future_FULFILLED, "Expected this.ptr to be 1p, was %p\n", was );
 
Index: libcfa/src/device/cpu.cfa
===================================================================
--- libcfa/src/device/cpu.cfa	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ libcfa/src/device/cpu.cfa	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -239,6 +239,5 @@
 // Returns a 2D array of instances of size [cpu count][cache levels]
 // where cache level doesn't include instruction caches
-raw_cache_instance ** build_raw_cache_table(unsigned cpus_c, idx_range_t cpus, unsigned idxs, unsigned cache_levels)
-{
+raw_cache_instance ** build_raw_cache_table(unsigned cpus_c, idx_range_t cpus, unsigned idxs, unsigned cache_levels) {
 	raw_cache_instance ** raw = alloc(cpus_c, '\0'`fill);
 
Index: libcfa/src/iostream.hfa
===================================================================
--- libcfa/src/iostream.hfa	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ libcfa/src/iostream.hfa	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Feb  6 18:35:54 2024
-// Update Count     : 743
+// Last Modified On : Sun Apr 21 07:32:19 2024
+// Update Count     : 744
 //
 
@@ -160,7 +160,7 @@
 
 // tuples
-forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
-	ostype & ?|?( ostype & os, T arg, Params rest );
-	void ?|?( ostype & os, T arg, Params rest );
+forall( ostype &, T, List ... | writeable( T, ostype ) | { ostype & ?|?( ostype &, List ); } ) {
+	ostype & ?|?( ostype & os, T arg, List rest );
+	void ?|?( ostype & os, T arg, List rest );
 } // distribution
 
Index: libcfa/src/stdlib.cfa
===================================================================
--- libcfa/src/stdlib.cfa	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ libcfa/src/stdlib.cfa	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jan 28 17:10:29 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Mar 17 08:25:32 2024
-// Update Count     : 699
+// Last Modified On : Sun Apr 21 16:17:22 2024
+// Update Count     : 700
 //
 
@@ -31,6 +31,6 @@
 // Cforall allocation/deallocation and constructor/destructor, array types
 
-forall( T & | sized(T), TT... | { void ?{}( T &, TT ); } )
-T * anew( size_t dim, TT p ) {
+forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } )
+T * anew( size_t dim, Parms p ) {
 	T * arr = alloc( dim );
 	for ( i; dim ) {
@@ -51,6 +51,6 @@
 } // adelete
 
-forall( T & | sized(T) | { void ^?{}( T & ); }, TT... | { void adelete( TT ); } )
-void adelete( T arr[], TT rest ) {
+forall( T & | sized(T) | { void ^?{}( T & ); }, List ... | { void adelete( List ); } )
+void adelete( T arr[], List rest ) {
 	if ( arr ) {										// ignore null
 		size_t dim = malloc_size( arr ) / sizeof( T );
Index: libcfa/src/stdlib.hfa
===================================================================
--- libcfa/src/stdlib.hfa	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ libcfa/src/stdlib.hfa	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jan 28 17:12:35 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Apr 15 22:11:51 2024
-// Update Count     : 817
+// Last Modified On : Tue Apr 23 14:05:21 2024
+// Update Count     : 963
 //
 
@@ -47,5 +47,5 @@
 
 static inline forall( T & | sized(T) ) {
-	// CFA safe equivalents, i.e., implicit size specification
+	// CFA safe equivalents, i.e., implicit size specification, eliminate return-type cast
 
 	T * malloc( void ) {
@@ -64,7 +64,11 @@
 	} // calloc
 
-	T * resize( T * ptr, size_t size ) {				// CFA resize
-		if ( _Alignof(T) <= libAlign() ) return (T *)resize( (void *)ptr, size ); // CFA resize
+	T * resize( T * ptr, size_t size ) {
+		if ( _Alignof(T) <= libAlign() ) return (T *)resize( (void *)ptr, size ); // C resize
 		else return (T *)resize( (void *)ptr, _Alignof(T), size ); // CFA resize
+	} // resize
+
+	T * resize( T * ptr, size_t alignment, size_t size ) {
+		return (T *)resize( (void *)ptr, alignment, size ); // CFA resize
 	} // resize
 
@@ -74,4 +78,8 @@
 	} // realloc
 
+	T * realloc( T * ptr, size_t alignment, size_t size ) {
+		return (T *)realloc( (void *)ptr, alignment, size ); // CFA realloc
+	} // realloc
+
 	T * reallocarray( T * ptr, size_t dim ) {			// CFA reallocarray
 		if ( _Alignof(T) <= libAlign() ) return (T *)reallocarray( (void *)ptr, dim, sizeof(T) ); // C reallocarray
@@ -79,4 +87,8 @@
 	} // realloc
 
+	T * reallocarray( T * ptr, size_t alignment, size_t dim ) {
+		return (T *)reallocarray( (void *)ptr, alignment, dim ); // CFA reallocarray
+	} // realloc
+
 	T * memalign( size_t align ) {
 		return (T *)memalign( align, sizeof(T) );		// C memalign
@@ -87,5 +99,5 @@
 	} // amemalign
 
-	T * cmemalign( size_t align, size_t dim  ) {
+	T * cmemalign( size_t align, size_t dim ) {
 		return (T *)cmemalign( align, dim, sizeof(T) );	// CFA cmemalign
 	} // cmemalign
@@ -109,5 +121,6 @@
 
 /*
-	FIX ME : fix alloc interface after Ticker Number 214 is resolved, define and add union to S_fill. Then, modify postfix-fill functions to support T * with nmemb, char, and T object of any size. Finally, change alloc_internal.
+	FIX ME : fix alloc interface after Ticker Number 214 is resolved, define and add union to S_fill. Then, modify
+	postfix-fill functions to support T * with nmemb, char, and T object of any size. Finally, change alloc_internal.
 	Or, just follow the instructions below for that.
 
@@ -153,19 +166,35 @@
 */
 
-typedef struct S_align { inline size_t;  } T_align;
-typedef struct S_resize { inline void *;  }	T_resize;
-
-forall( T & ) {
-	struct S_fill { char tag; char c; size_t size; T * at; char t[50]; };
-	struct S_realloc { inline T *; };
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#pragma GCC diagnostic ignored "-Wuninitialized"
+
+struct T_align { size_t align; };
+struct T_resize { void * addr; };
+struct T_realloc { void * addr; };
+forall( T & ) struct T_fill {
+	// 'N' => no fill, 'c' => fill with character c, 'a' => fill first N array elements from another array,
+	// 'A' => fill all array elements from another array, 'T' => fill using a T value.
+	char tag;
+	size_t nelem;   // number of elements copied from "at" (used with tag 'a')
+//	union {
+		char c;
+		T * at;
+		char t[64]; // T t;
+//	};
+};
+
+#pragma GCC diagnostic pop
+
+static inline {
+	T_align ?`align( size_t a ) { return (T_align){ a }; }
+	T_resize ?`resize( void * a ) { return (T_resize){ a }; }
+	T_realloc ?`realloc( void * a ) { return (T_realloc){ a }; }
 }
 
-static inline T_align ?`align( size_t a ) { return (T_align){a}; }
-static inline T_resize ?`resize( void * a )	{ return (T_resize){a}; }
-
-extern "C" ssize_t write(int fd, const void *buf, size_t count);
 static inline forall( T & | sized(T) ) {
-	S_fill(T) ?`fill ( T t ) {
-		S_fill(T) ret = { 't' };
+	T_fill(T) ?`fill( char c ) { return (T_fill(T)){ 'c', 0, c }; }
+	T_fill(T) ?`fill( T t ) {
+		T_fill(T) ret = { 'T' };
 		size_t size = sizeof(T);
 		if ( size > sizeof(ret.t) ) {
@@ -175,79 +204,83 @@
 		return ret;
 	}
-	S_fill(T) ?`fill ( zero_t ) = void; // FIX ME: remove this once ticket 214 is resolved
-	S_fill(T) ?`fill ( T * a ) { return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved
-	S_fill(T) ?`fill ( char c ) { return (S_fill(T)){ 'c', c };	}
-	S_fill(T) ?`fill ( T a[], size_t nmemb ) { return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; }
-
-	S_realloc(T) ?`realloc ( T * a ) { return (S_realloc(T)){a}; }
-
-	T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
-		T * ptr = NULL;
-		size_t size = sizeof(T);
+	T_fill(T) ?`fill( T a[] ) { return (T_fill(T)){ 'A', 0, '\0', a }; } // FIX ME: remove this once ticket 214 is resolved
+	T_fill(T) ?`fill( T a[], size_t nelem ) { return (T_fill(T)){ 'a', nelem * sizeof(T), '\0', a }; }
+
+	// private interface
+	T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t Align, T_fill(T) Fill ) {
+		T * ptr;
+		size_t tsize = sizeof(T);
 		size_t copy_end = 0;
 
-		if ( Resize ) {
-			ptr = (T*)(void *)resize( (void *)Resize, Align, Dim * size );
-		} else if ( Realloc ) {
-			if ( Fill.tag != '0' ) copy_end = min(malloc_size( Realloc ), Dim * size );
-			ptr = (T *)(void *)realloc( (void *)Realloc, Align, Dim * size );
+		if ( Resize.addr ) {
+			ptr = (T *)(void *)resize( Resize.addr, Align, Dim * tsize );
+		} else if ( Realloc.addr ) {
+			if ( Fill.tag != 'N' ) copy_end = min(malloc_size( Realloc.addr ), Dim * tsize );
+			ptr = (T *)(void *)realloc( Realloc.addr, Align, Dim * tsize );
 		} else {
-			ptr = (T *)(void *) memalign( Align, Dim * size );
-		}
+			ptr = (T *)(void *)memalign( Align, Dim * tsize );
+		} // if
 
 		if ( Fill.tag == 'c' ) {
-			memset( (char *)ptr + copy_end, (int)Fill.c, Dim * size - copy_end );
-		} else if ( Fill.tag == 't' ) {
-			for ( i; copy_end ~ Dim * size ~ size ) {
-				#pragma GCC diagnostic push
-				#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-				assert( size <= sizeof(Fill.t) );
-				memcpy( (char *)ptr + i, &Fill.t, size );
-				#pragma GCC diagnostic pop
-			}
+			memset( (char *)ptr + copy_end, (int)Fill.c, Dim * tsize - copy_end );
+		} else if ( Fill.tag == 'T' ) {
+			for ( i; copy_end ~ Dim * tsize ~ tsize ) {
+				assert( tsize <= sizeof(Fill.t) );
+				memcpy( (char *)ptr + i, &Fill.t, tsize );
+			} // for
 		} else if ( Fill.tag == 'a' ) {
-			memcpy( (char *)ptr + copy_end, Fill.at, min(Dim * size - copy_end, Fill.size) );
-		} else if ( Fill.tag == 'T' ) {
-			memcpy( (char *)ptr + copy_end, Fill.at, Dim * size );
-		}
-
+			memcpy( (char *)ptr + copy_end, Fill.at, min( Dim * tsize - copy_end, Fill.nelem ) );
+		} else if ( Fill.tag == 'A' ) {
+			memcpy( (char *)ptr + copy_end, Fill.at, Dim * tsize );
+		} // if
 		return ptr;
 	} // alloc_internal$
 
-	forall( TT ... | { T * alloc_internal$( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
-		T * alloc_internal$( void *, T *, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest ) {
-	        return alloc_internal$( Resize, (T*)0p, Align, Dim, Fill, rest);
+	// Dim is a fixed (optional first) parameter, and hence is not set using a postfix function. A dummy parameter is
+	// being overwritten by the postfix argument in the ttype.
+	forall( List ... | { T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t Align, T_fill(T) Fill, List ); } ) {
+		// middle interface
+		T * alloc_internal$( size_t Dim, T_resize dummy, T_realloc Realloc, size_t Align, T_fill(T) Fill, T_resize Resize, List rest ) {
+	        return alloc_internal$( Dim, Resize, (T_realloc){0p}, Align, Fill, rest );
 		}
-
-		T * alloc_internal$( void *, T *, size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest ) {
-	        return alloc_internal$( (void*)0p, Realloc, Align, Dim, Fill, rest);
+		T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc dummy, size_t Align, T_fill(T) Fill, T_realloc Realloc, List rest ) {
+	        return alloc_internal$( Dim, (T_resize){0p}, Realloc, Align, Fill, rest );
 		}
-
-		T * alloc_internal$( void * Resize, T * Realloc, size_t, size_t Dim, S_fill(T) Fill, T_align Align, TT rest ) {
-	        return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest);
+		T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t dummy, T_fill(T) Fill, T_align Align, List rest ) {
+	        return alloc_internal$( Dim, Resize, Realloc, Align.align, Fill, rest );
 		}
-
-		T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T), S_fill(T) Fill, TT rest ) {
-	        return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest );
+		T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t Align, T_fill(T) dummy, T_fill(T) Fill, List rest ) {
+	        return alloc_internal$( Dim, Resize, Realloc, Align, Fill, rest );
 		}
-
-	    T * alloc( TT all ) {
-	    	return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all );
+		// public interface
+	    T * alloc( List rest ) {
+	    	return alloc_internal$( (size_t)1, (T_resize){0p}, (T_realloc){0p}, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (T_fill(T)){'N'}, rest );
 	    }
-
-	    T * alloc( size_t dim, TT all ) {
-	    	return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all );
+	    T * alloc( size_t Dim, List rest ) {
+	    	return alloc_internal$( Dim, (T_resize){0p}, (T_realloc){0p}, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (T_fill(T)){'N'}, rest );
 	    }
-	} // distribution TT
+	} // distribution List
 } // distribution T
 
 static inline forall( T & | sized(T) ) {
 	// CFA safe initialization/copy, i.e., implicit size specification, non-array types
-	T * memset( T * dest, char fill ) {
-		return (T *)memset( dest, fill, sizeof(T) );
+	T * memset( T * dest, char fill ) {					// all combinations of pointer/reference
+		return (T *)memset( dest, fill, sizeof(T) );	// C memset
 	} // memset
-
-	T * memcpy( T * dest, const T * src ) {
-		return (T *)memcpy( dest, src, sizeof(T) );
+	T * memset( T & dest, char fill ) {
+		return (T *)memset( &dest, fill, sizeof(T) );	// C memset
+	} // memset
+
+	T * memcpy( T * dest, const T * src ) {				// all combinations of pointer/reference
+		return (T *)memcpy( dest, src, sizeof(T) );		// C memcpy
+	} // memcpy
+	T * memcpy( T & dest, const T & src ) {
+		return (T *)memcpy( &dest, &src, sizeof(T) );	// C memcpy
+	} // memcpy
+	T * memcpy( T * dest, const T & src ) {
+		return (T *)memcpy( dest, &src, sizeof(T) );	// C memcpy
+	} // memcpy
+	T * memcpy( T & dest, const T * src ) {
+		return (T *)memcpy( &dest, src, sizeof(T) );	// C memcpy
 	} // memcpy
 
@@ -263,10 +296,10 @@
 
 // CFA deallocation for multiple objects
-static inline forall( T & )							// FIX ME, problems with 0p in list
+static inline forall( T & )
 void free( T * ptr ) {
 	free( (void *)ptr );								// C free
 } // free
-static inline forall( T &, TT ... | { void free( TT ); } )
-void free( T * ptr, TT rest ) {
+static inline forall( T &, List ... | { void free( List ); } )
+void free( T * ptr, List rest ) {
 	free( ptr );
 	free( rest );
@@ -274,6 +307,6 @@
 
 // CFA allocation/deallocation and constructor/destructor, non-array types
-static inline forall( T & | sized(T), TT ... | { void ?{}( T &, TT ); } )
-T * new( TT p ) {
+static inline forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } )
+T * new( Parms p ) {
 	return &(*(T *)malloc()){ p };						// run constructor
 } // new
@@ -287,6 +320,6 @@
 	free( ptr );										// always call free
 } // delete
-static inline forall( T &, TT ... | { void ^?{}( T & ); void delete( TT ); } )
-void delete( T * ptr, TT rest ) {
+static inline forall( T &, List ... | { void ^?{}( T & ); void delete( List ); } )
+void delete( T * ptr, List rest ) {
 	delete( ptr );
 	delete( rest );
@@ -294,7 +327,8 @@
 
 // CFA allocation/deallocation and constructor/destructor, array types
-forall( T & | sized(T), TT ... | { void ?{}( T &, TT ); } ) T * anew( size_t dim, TT p );
+forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } ) T * anew( size_t dim, Parms p );
 forall( T & | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] );
-forall( T & | sized(T) | { void ^?{}( T & ); }, TT ... | { void adelete( TT ); } ) void adelete( T arr[], TT rest );
+forall( T & | sized(T) | { void ^?{}( T & ); }, List ... | { void adelete( List ); } ) void adelete( T arr[], List rest );
+
 //---------------------------------------
 
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: c/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
Index: tests/alloc.cfa
===================================================================
--- tests/alloc.cfa	(revision cf191acabcbe38d3f82a9149c4febffefea40a9a)
+++ tests/alloc.cfa	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -10,6 +10,6 @@
 // Created On       : Wed Feb  3 07:56:22 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Oct 14 09:31:39 2022
-// Update Count     : 491
+// Last Modified On : Tue Apr 23 14:04:11 2024
+// Update Count     : 492
 //
 
@@ -240,5 +240,5 @@
 	free( stp );
 
-	posix_memalign( &stp, Alignment );                  // CFA posix_memalign
+	posix_memalign( &stp, Alignment );					// CFA posix_memalign
 	*stp = (Struct){ 42, 42.5 };
 	assert( (uintptr_t)stp % Alignment == 0 );
@@ -275,5 +275,5 @@
 	sout | nl;
 
-	stp = alloc( dim, Alignment`align );                // CFA array memalign
+	stp = alloc( dim, Alignment`align );				// CFA array memalign
 	assert( (uintptr_t)stp % Alignment == 0 );
 	for ( i; dim ) { stp[i] = (Struct){ 42, 42.5 }; }
@@ -316,7 +316,7 @@
 	sout | nl;
 
-	memset( &st, fill );                                // CFA memset, type safe
+	memset( st, fill );									// CFA memset, type safe
 	sout | "CFA memset" | hex(st.x) | hex(st.y);
-	memcpy( &st1, &st );                                // CFA memcpy, type safe
+	memcpy( st1, st );									// CFA memcpy, type safe
 	sout | "CFA memcpy" | hex(st1.x) | hex(st1.y);
 
Index: tools/test_time.py
===================================================================
--- tools/test_time.py	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
+++ tools/test_time.py	(revision 7042c60b5ac335636cead43392db79c8e35cedf8)
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+"""Inspect test results for timing information.
+
+Run on a file that contains results from tests/test.py to see results.
+"""
+
+
+import argparse
+from datetime import timedelta
+import re
+import statistics
+
+
+def parse_args(args=None):
+    parser = argparse.ArgumentParser(
+        description='Summarize performance results from a test run.')
+    parser.add_argument('result_file', type=argparse.FileType('r'))
+    return parser.parse_args(args)
+
+
+def str_to_time(time_str):
+    match = re.search('([0-9]+):([0-9]+)[.]([0-9]+)', time_str)
+    if not match:
+        raise Exception('Badly formatted')
+    minutes, seconds, milli = (int(x) for x in match.groups())
+    return timedelta(minutes=minutes, seconds=seconds, milliseconds=milli)
+
+
+def line_to_entry(line):
+    match = re.search('([^\t ]+) +PASSED +C( n/a|.*) - R( n/a|.*)', line)
+    if not match:
+        return None
+    test_id, compile_str, run_str = match.groups()
+    compile_time = None if ' n/a' == compile_str else str_to_time(compile_str)
+    run_time = None if ' n/a' == run_str else str_to_time(run_str)
+    return test_id, compile_time, run_time
+
+
+def iter_file_entries(open_file):
+    with open_file as file:
+        for line in file.readlines():
+            entry = line_to_entry(line)
+            if entry is not None:
+                yield entry
+
+
+def entry_to_compile_seconds(entry):
+    _id, compile_time, _run_time = entry
+    return compile_time.total_seconds()
+
+
+if '__main__' == __name__:
+    args = parse_args()
+    mean = statistics.geometric_mean(
+        map(entry_to_compile_seconds, iter_file_entries(args.result_file)))
+    print('Source File:', args.result_file.name)
+    print('Geometric Mean:', mean)
