Index: nkinsfile
===================================================================
--- Jenkinsfile	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ 	(revision )
@@ -1,514 +1,0 @@
-#!groovy
-
-import groovy.transform.Field
-
-// For skipping stages
-import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
-
-//===========================================================================================================
-// Main loop of the compilation
-//===========================================================================================================
-
-node('master') {
-	// Globals
-	BuildDir  = pwd tmp: true
-	SrcDir    = pwd tmp: false
-	Settings  = null
-	StageName = ''
-
-	// Local variables
-	def err = null
-	def log_needed = false
-
-	currentBuild.result = "SUCCESS"
-
-	try {
-		//Wrap build to add timestamp to command line
-		wrap([$class: 'TimestamperBuildWrapper']) {
-
-			Settings = prepare_build()
-
-			node(Settings.Architecture.node) {
-				BuildDir  = pwd tmp: true
-				SrcDir    = pwd tmp: false
-
-				clean()
-
-				checkout()
-
-				build()
-
-				test()
-
-				benchmark()
-
-				build_doc()
-
-				publish()
-			}
-
-			// Update the build directories when exiting the node
-			BuildDir  = pwd tmp: true
-			SrcDir    = pwd tmp: false
-		}
-	}
-
-	//If an exception is caught we need to change the status and remember to
-	//attach the build log to the email
-	catch (Exception caughtError) {
-		//rethrow error later
-		err = caughtError
-
-		echo err.toString()
-
-		//An error has occured, the build log is relevent
-		log_needed = true
-
-		//Store the result of the build log
-		currentBuild.result = "${StageName} FAILURE".trim()
-	}
-
-	finally {
-		//Send email with final results if this is not a full build
-		email(log_needed)
-
-		echo 'Build Completed'
-
-		/* Must re-throw exception to propagate error */
-		if (err) {
-			throw err
-		}
-	}
-}
-//===========================================================================================================
-// Main compilation routines
-//===========================================================================================================
-def clean() {
-	build_stage('Cleanup', true) {
-		// clean the build by wipping the build directory
-		dir(BuildDir) {
-			deleteDir()
-		}
-	}
-}
-
-//Compilation script is done here but environnement set-up and error handling is done in main loop
-def checkout() {
-	build_stage('Checkout', true) {
-		//checkout the source code and clean the repo
-		final scmVars = checkout scm
-		Settings.GitNewRef = scmVars.GIT_COMMIT
-		Settings.GitOldRef = scmVars.GIT_PREVIOUS_COMMIT
-
-		echo GitLogMessage()
-	}
-}
-
-def build() {
-	// build_stage('Build', true) {
-	// 	// Build outside of the src tree to ease cleaning
-	// 	dir (BuildDir) {
-	// 		//Configure the conpilation (Output is not relevant)
-	// 		//Use the current directory as the installation target so nothing escapes the sandbox
-	// 		//Also specify the compiler by hand
-	// 		targets=""
-	// 		if( Settings.RunAllTests || Settings.RunBenchmark ) {
-	// 			targets="--with-target-hosts='host:debug,host:nodebug'"
-	// 		} else {
-	// 			targets="--with-target-hosts='host:debug'"
-	// 		}
-
-	// 		sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} ${targets} --quiet"
-
-	// 		//Compile the project
-	// 		sh 'make -j 8 --no-print-directory'
-	// 	}
-	// }
-
-	debug = true
-	release = Settings.RunAllTests || Settings.RunBenchmark
-	build_stage('Build : configure', true) {
-		// Build outside of the src tree to ease cleaning
-		dir (BuildDir) {
-			//Configure the conpilation (Output is not relevant)
-			//Use the current directory as the installation target so nothing escapes the sandbox
-			//Also specify the compiler by hand
-			targets=""
-			if( Settings.RunAllTests || Settings.RunBenchmark ) {
-				targets="--with-target-hosts='host:debug,host:nodebug'"
-			} else {
-				targets="--with-target-hosts='host:debug'"
-			}
-
-			sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} ${targets} --quiet"
-
-			// Configure libcfa
-			sh 'make -j 8 --no-print-directory configure-libcfa'
-		}
-	}
-
-	build_stage('Build : cfa-cpp', true) {
-		// Build outside of the src tree to ease cleaning
-		dir (BuildDir) {
-			// Build driver
-			sh 'make -j 8 --no-print-directory -C driver'
-
-			// Build translator
-			sh 'make -j 8 --no-print-directory -C src'
-		}
-	}
-
-	build_stage('Build : libcfa(debug)', debug) {
-		// Build outside of the src tree to ease cleaning
-		dir (BuildDir) {
-			sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-debug"
-		}
-	}
-
-	build_stage('Build : libcfa(nodebug)', release) {
-		// Build outside of the src tree to ease cleaning
-		dir (BuildDir) {
-			sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-nodebug"
-		}
-	}
-}
-
-def test() {
-	build_stage('Test: short', !Settings.RunAllTests) {
-		dir (BuildDir) {
-			//Run the tests from the tests directory
-			sh 'make --no-print-directory -C tests'
-		}
-	}
-
-	build_stage('Test: full', Settings.RunAllTests) {
-		dir (BuildDir) {
-			//Run the tests from the tests directory
-			sh 'make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=yes'
-			sh 'make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=no '
-		}
-	}
-}
-
-def benchmark() {
-	build_stage('Benchmark', Settings.RunBenchmark) {
-		dir (BuildDir) {
-			//Append bench results
-			sh "make --no-print-directory -C benchmark jenkins"
-		}
-	}
-}
-
-def build_doc() {
-	build_stage('Documentation', Settings.BuildDocumentation) {
-		dir ('doc/user') {
-			make_doc()
-		}
-
-		dir ('doc/refrat') {
-			make_doc()
-		}
-	}
-}
-
-def publish() {
-	build_stage('Publish', true) {
-
-		if( Settings.Publish && !Settings.RunBenchmark ) { echo 'No results to publish!!!' }
-
-		def groupCompile = new PlotGroup('Compilation', 'seconds', true)
-		def groupConcurrency = new PlotGroup('Concurrency', 'nanoseconds', false)
-
-		//Then publish the results
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'compile'  , groupCompile    , 'Compilation')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch', groupConcurrency, 'Context Switching')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex'    , groupConcurrency, 'Mutual Exclusion')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'signal'   , groupConcurrency, 'Internal and External Scheduling')
-	}
-}
-
-//===========================================================================================================
-//Routine responsible of sending the email notification once the build is completed
-//===========================================================================================================
-def GitLogMessage() {
-	if (!Settings || !Settings.GitOldRef || !Settings.GitNewRef) return "\nERROR retrieveing git information!\n"
-
-	sh "${SrcDir}/tools/PrettyGitLogs.sh ${SrcDir} ${BuildDir} ${Settings.GitOldRef} ${Settings.GitNewRef}"
-
-	def gitUpdate = readFile("${BuildDir}/GIT_UPDATE")
-	def gitLog    = readFile("${BuildDir}/GIT_LOG")
-	def gitDiff   = readFile("${BuildDir}/GIT_DIFF")
-
-	return """
-<pre>
-The branch ${env.BRANCH_NAME} has been updated.
-${gitUpdate}
-</pre>
-
-<p>Check console output at ${env.BUILD_URL} to view the results.</p>
-
-<p>- Status --------------------------------------------------------------</p>
-
-<p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p>
-
-<p>- Log -----------------------------------------------------------------</p>
-
-<pre>
-${gitLog}
-</pre>
-
-<p>-----------------------------------------------------------------------</p>
-<pre>
-Summary of changes:
-${gitDiff}
-</pre>
-"""
-}
-
-//Standard build email notification
-def email(boolean log) {
-	//Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
-	//Configurations for email format
-	echo 'Notifying users of result'
-
-	def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()
-	def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}"
-	def email_body = """<p>This is an automated email from the Jenkins build machine. It was
-generated because of a git hooks/post-receive script following
-a ref change which was pushed to the C\u2200 repository.</p>
-""" + GitLogMessage()
-
-	def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"
-
-	if( Settings && !Settings.Silent ) {
-		//send email notification
-		emailext body: email_body, subject: email_subject, to: email_to, attachLog: log
-	} else {
-		echo "Would send email to: ${email_to}"
-		echo "With title: ${email_subject}"
-		echo "Content: \n${email_body}"
-	}
-}
-
-//===========================================================================================================
-// Helper classes/variables/routines
-//===========================================================================================================
-//Description of a compiler (Must be serializable since pipelines are persistent)
-class CC_Desc implements Serializable {
-	public String name
-	public String CXX
-	public String CC
-
-	CC_Desc(String name, String CXX, String CC) {
-		this.name = name
-		this.CXX = CXX
-		this.CC = CC
-	}
-}
-
-//Description of an architecture (Must be serializable since pipelines are persistent)
-class Arch_Desc implements Serializable {
-	public String name
-	public String flags
-	public String node
-
-	Arch_Desc(String name, String flags, String node) {
-		this.name  = name
-		this.flags = flags
-		this.node  = node
-	}
-}
-
-class BuildSettings implements Serializable {
-	public final CC_Desc Compiler
-	public final Arch_Desc Architecture
-	public final Boolean RunAllTests
-	public final Boolean RunBenchmark
-	public final Boolean BuildDocumentation
-	public final Boolean Publish
-	public final Boolean Silent
-	public final Boolean IsSandbox
-	public final String DescLong
-	public final String DescShort
-
-	public String GitNewRef
-	public String GitOldRef
-
-	BuildSettings(java.util.Collections$UnmodifiableMap param, String branch) {
-		switch( param.Compiler ) {
-			case 'gcc-6':
-				this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6')
-			break
-			case 'gcc-5':
-				this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5')
-			break
-			case 'gcc-4.9':
-				this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9')
-			break
-			case 'clang':
-				this.Compiler = new CC_Desc('clang', 'clang++', 'gcc-6')
-			break
-			default :
-				error "Unhandled compiler : ${cc}"
-		}
-
-		switch( param.Architecture ) {
-			case 'x64':
-				this.Architecture = new Arch_Desc('x64', '--host=x86_64', 'x64')
-			break
-			case 'x86':
-				this.Architecture = new Arch_Desc('x86', '--host=i386', 'x86')
-			break
-			default :
-				error "Unhandled architecture : ${arch}"
-		}
-
-		this.IsSandbox          = (branch == "jenkins-sandbox")
-		this.RunAllTests        = param.RunAllTests
-		this.RunBenchmark       = param.RunBenchmark
-		this.BuildDocumentation = param.BuildDocumentation
-		this.Publish            = param.Publish
-		this.Silent             = param.Silent
-
-		def full = param.RunAllTests ? " (Full)" : ""
-		this.DescShort = "${ this.Compiler.name }:${ this.Architecture.name }${full}"
-
-		this.DescLong = """Compiler 	         : ${ this.Compiler.name } (${ this.Compiler.CXX }/${ this.Compiler.CC })
-Architecture            : ${ this.Architecture.name }
-Arc Flags               : ${ this.Architecture.flags }
-Run All Tests           : ${ this.RunAllTests.toString() }
-Run Benchmark           : ${ this.RunBenchmark.toString() }
-Build Documentation     : ${ this.BuildDocumentation.toString() }
-Publish                 : ${ this.Publish.toString() }
-Silent                  : ${ this.Silent.toString() }
-"""
-
-		this.GitNewRef = ''
-		this.GitOldRef = ''
-	}
-}
-
-class PlotGroup implements Serializable {
-	public String name
-	public String unit
-	public boolean log
-
-	PlotGroup(String name, String unit, boolean log) {
-		this.name = name
-		this.unit = unit
-		this.log = log
-	}
-}
-
-def prepare_build() {
-	// prepare the properties
-	properties ([ 													\
-		[$class: 'ParametersDefinitionProperty', 								\
-			parameterDefinitions: [ 									\
-				[$class: 'ChoiceParameterDefinition',						\
-					description: 'Which compiler to use',					\
-					name: 'Compiler',									\
-					choices: 'gcc-6\ngcc-5\ngcc-4.9\nclang',					\
-					defaultValue: 'gcc-6',								\
-				],												\
-				[$class: 'ChoiceParameterDefinition',						\
-					description: 'The target architecture',					\
-					name: 'Architecture',								\
-					choices: 'x64\nx86',								\
-					defaultValue: 'x64',								\
-				],												\
-				[$class: 'BooleanParameterDefinition',  						\
-					description: 'If false, only the quick test suite is ran', 		\
-					name: 'RunAllTests', 								\
-					defaultValue: false,  								\
-				], 												\
-				[$class: 'BooleanParameterDefinition',  						\
-					description: 'If true, jenkins also runs benchmarks', 		\
-					name: 'RunBenchmark', 								\
-					defaultValue: false,  								\
-				], 												\
-				[$class: 'BooleanParameterDefinition',  						\
-					description: 'If true, jenkins also builds documentation', 		\
-					name: 'BuildDocumentation', 							\
-					defaultValue: true,  								\
-				],												\
-				[$class: 'BooleanParameterDefinition',  						\
-					description: 'If true, jenkins also publishes results', 		\
-					name: 'Publish', 									\
-					defaultValue: false,  								\
-				],												\
-				[$class: 'BooleanParameterDefinition',  						\
-					description: 'If true, jenkins will not send emails', 		\
-					name: 'Silent', 									\
-					defaultValue: false,  								\
-				],												\
-			],
-		]])
-
-	// It's unfortunate but it looks like we need to checkout the entire repo just to get the pretty git printer
-	checkout scm
-
-	final settings = new BuildSettings(params, env.BRANCH_NAME)
-
-	currentBuild.description = settings.DescShort
-	echo                       settings.DescLong
-
-	return settings
-}
-
-def build_stage(String name, boolean run, Closure block ) {
-	StageName = name
-	echo " -------- ${StageName} -------- "
-	if(run) {
-		stage(name, block)
-	} else {
-		stage(name) { Utils.markStageSkippedForConditional(STAGE_NAME) }
-	}
-}
-
-def make_doc() {
-	def err = null
-	try {
-		sh 'make clean > /dev/null'
-		sh 'make > /dev/null 2>&1'
-	}
-	catch (Exception caughtError) {
-		err = caughtError //rethrow error later
-		sh 'cat build/*.log'
-	}
-	finally {
-		if (err) throw err // Must re-throw exception to propagate error
-	}
-}
-
-def do_plot(boolean new_data, String file, PlotGroup group, String title) {
-
-	if(new_data) {
-		echo "Publishing new data"
-	}
-
-	def series = new_data ? [[
-				file: "${file}.csv",
-				exclusionValues: '',
-				displayTableFlag: false,
-				inclusionFlag: 'OFF',
-				url: ''
-			]] : [];
-
-	echo "file is ${BuildDir}/benchmark/${file}.csv, group ${group}, title ${title}"
-	dir("${BuildDir}/benchmark/") {
-		plot csvFileName: "cforall-${env.BRANCH_NAME}-${file}.csv",
-			csvSeries: series,
-			group: "${group.name}",
-			title: "${title}",
-			style: 'lineSimple',
-			exclZero: false,
-			keepRecords: false,
-			logarithmic: group.log,
-			numBuilds: '120',
-			useDescr: true,
-			yaxis: group.unit,
-			yaxisMaximum: '',
-			yaxisMinimum: ''
-	}
-}
Index: Jenkinsfile_disabled
===================================================================
--- Jenkinsfile_disabled	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
+++ Jenkinsfile_disabled	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -0,0 +1,514 @@
+#!groovy
+
+import groovy.transform.Field
+
+// For skipping stages
+import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
+
+//===========================================================================================================
+// Main loop of the compilation
+//===========================================================================================================
+
+node('master') {
+	// Globals
+	BuildDir  = pwd tmp: true
+	SrcDir    = pwd tmp: false
+	Settings  = null
+	StageName = ''
+
+	// Local variables
+	def err = null
+	def log_needed = false
+
+	currentBuild.result = "SUCCESS"
+
+	try {
+		//Wrap build to add timestamp to command line
+		wrap([$class: 'TimestamperBuildWrapper']) {
+
+			Settings = prepare_build()
+
+			node(Settings.Architecture.node) {
+				BuildDir  = pwd tmp: true
+				SrcDir    = pwd tmp: false
+
+				clean()
+
+				checkout()
+
+				build()
+
+				test()
+
+				benchmark()
+
+				build_doc()
+
+				publish()
+			}
+
+			// Update the build directories when exiting the node
+			BuildDir  = pwd tmp: true
+			SrcDir    = pwd tmp: false
+		}
+	}
+
+	//If an exception is caught we need to change the status and remember to
+	//attach the build log to the email
+	catch (Exception caughtError) {
+		//rethrow error later
+		err = caughtError
+
+		echo err.toString()
+
+		//An error has occured, the build log is relevent
+		log_needed = true
+
+		//Store the result of the build log
+		currentBuild.result = "${StageName} FAILURE".trim()
+	}
+
+	finally {
+		//Send email with final results if this is not a full build
+		email(log_needed)
+
+		echo 'Build Completed'
+
+		/* Must re-throw exception to propagate error */
+		if (err) {
+			throw err
+		}
+	}
+}
+//===========================================================================================================
+// Main compilation routines
+//===========================================================================================================
+def clean() {
+	build_stage('Cleanup', true) {
+		// clean the build by wipping the build directory
+		dir(BuildDir) {
+			deleteDir()
+		}
+	}
+}
+
+//Compilation script is done here but environnement set-up and error handling is done in main loop
+def checkout() {
+	build_stage('Checkout', true) {
+		//checkout the source code and clean the repo
+		final scmVars = checkout scm
+		Settings.GitNewRef = scmVars.GIT_COMMIT
+		Settings.GitOldRef = scmVars.GIT_PREVIOUS_COMMIT
+
+		echo GitLogMessage()
+	}
+}
+
+def build() {
+	// build_stage('Build', true) {
+	// 	// Build outside of the src tree to ease cleaning
+	// 	dir (BuildDir) {
+	// 		//Configure the conpilation (Output is not relevant)
+	// 		//Use the current directory as the installation target so nothing escapes the sandbox
+	// 		//Also specify the compiler by hand
+	// 		targets=""
+	// 		if( Settings.RunAllTests || Settings.RunBenchmark ) {
+	// 			targets="--with-target-hosts='host:debug,host:nodebug'"
+	// 		} else {
+	// 			targets="--with-target-hosts='host:debug'"
+	// 		}
+
+	// 		sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} ${targets} --quiet"
+
+	// 		//Compile the project
+	// 		sh 'make -j 8 --no-print-directory'
+	// 	}
+	// }
+
+	debug = true
+	release = Settings.RunAllTests || Settings.RunBenchmark
+	build_stage('Build : configure', true) {
+		// Build outside of the src tree to ease cleaning
+		dir (BuildDir) {
+			//Configure the conpilation (Output is not relevant)
+			//Use the current directory as the installation target so nothing escapes the sandbox
+			//Also specify the compiler by hand
+			targets=""
+			if( Settings.RunAllTests || Settings.RunBenchmark ) {
+				targets="--with-target-hosts='host:debug,host:nodebug'"
+			} else {
+				targets="--with-target-hosts='host:debug'"
+			}
+
+			sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} ${targets} --quiet"
+
+			// Configure libcfa
+			sh 'make -j 8 --no-print-directory configure-libcfa'
+		}
+	}
+
+	build_stage('Build : cfa-cpp', true) {
+		// Build outside of the src tree to ease cleaning
+		dir (BuildDir) {
+			// Build driver
+			sh 'make -j 8 --no-print-directory -C driver'
+
+			// Build translator
+			sh 'make -j 8 --no-print-directory -C src'
+		}
+	}
+
+	build_stage('Build : libcfa(debug)', debug) {
+		// Build outside of the src tree to ease cleaning
+		dir (BuildDir) {
+			sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-debug"
+		}
+	}
+
+	build_stage('Build : libcfa(nodebug)', release) {
+		// Build outside of the src tree to ease cleaning
+		dir (BuildDir) {
+			sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-nodebug"
+		}
+	}
+}
+
+def test() {
+	build_stage('Test: short', !Settings.RunAllTests) {
+		dir (BuildDir) {
+			//Run the tests from the tests directory
+			sh 'make --no-print-directory -C tests'
+		}
+	}
+
+	build_stage('Test: full', Settings.RunAllTests) {
+		dir (BuildDir) {
+			//Run the tests from the tests directory
+			sh 'make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=yes'
+			sh 'make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=no '
+		}
+	}
+}
+
+def benchmark() {
+	build_stage('Benchmark', Settings.RunBenchmark) {
+		dir (BuildDir) {
+			//Append bench results
+			sh "make --no-print-directory -C benchmark jenkins"
+		}
+	}
+}
+
+def build_doc() {
+	build_stage('Documentation', Settings.BuildDocumentation) {
+		dir ('doc/user') {
+			make_doc()
+		}
+
+		dir ('doc/refrat') {
+			make_doc()
+		}
+	}
+}
+
+def publish() {
+	build_stage('Publish', true) {
+
+		if( Settings.Publish && !Settings.RunBenchmark ) { echo 'No results to publish!!!' }
+
+		def groupCompile = new PlotGroup('Compilation', 'seconds', true)
+		def groupConcurrency = new PlotGroup('Concurrency', 'nanoseconds', false)
+
+		//Then publish the results
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'compile'  , groupCompile    , 'Compilation')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch', groupConcurrency, 'Context Switching')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex'    , groupConcurrency, 'Mutual Exclusion')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'signal'   , groupConcurrency, 'Internal and External Scheduling')
+	}
+}
+
+//===========================================================================================================
+//Routine responsible of sending the email notification once the build is completed
+//===========================================================================================================
+def GitLogMessage() {
+	if (!Settings || !Settings.GitOldRef || !Settings.GitNewRef) return "\nERROR retrieveing git information!\n"
+
+	sh "${SrcDir}/tools/PrettyGitLogs.sh ${SrcDir} ${BuildDir} ${Settings.GitOldRef} ${Settings.GitNewRef}"
+
+	def gitUpdate = readFile("${BuildDir}/GIT_UPDATE")
+	def gitLog    = readFile("${BuildDir}/GIT_LOG")
+	def gitDiff   = readFile("${BuildDir}/GIT_DIFF")
+
+	return """
+<pre>
+The branch ${env.BRANCH_NAME} has been updated.
+${gitUpdate}
+</pre>
+
+<p>Check console output at ${env.BUILD_URL} to view the results.</p>
+
+<p>- Status --------------------------------------------------------------</p>
+
+<p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p>
+
+<p>- Log -----------------------------------------------------------------</p>
+
+<pre>
+${gitLog}
+</pre>
+
+<p>-----------------------------------------------------------------------</p>
+<pre>
+Summary of changes:
+${gitDiff}
+</pre>
+"""
+}
+
+//Standard build email notification
+def email(boolean log) {
+	//Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
+	//Configurations for email format
+	echo 'Notifying users of result'
+
+	def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()
+	def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}"
+	def email_body = """<p>This is an automated email from the Jenkins build machine. It was
+generated because of a git hooks/post-receive script following
+a ref change which was pushed to the C\u2200 repository.</p>
+""" + GitLogMessage()
+
+	def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"
+
+	if( Settings && !Settings.Silent ) {
+		//send email notification
+		emailext body: email_body, subject: email_subject, to: email_to, attachLog: log
+	} else {
+		echo "Would send email to: ${email_to}"
+		echo "With title: ${email_subject}"
+		echo "Content: \n${email_body}"
+	}
+}
+
+//===========================================================================================================
+// Helper classes/variables/routines
+//===========================================================================================================
+//Description of a compiler (Must be serializable since pipelines are persistent)
+class CC_Desc implements Serializable {
+	public String name
+	public String CXX
+	public String CC
+
+	CC_Desc(String name, String CXX, String CC) {
+		this.name = name
+		this.CXX = CXX
+		this.CC = CC
+	}
+}
+
+//Description of an architecture (Must be serializable since pipelines are persistent)
+class Arch_Desc implements Serializable {
+	public String name
+	public String flags
+	public String node
+
+	Arch_Desc(String name, String flags, String node) {
+		this.name  = name
+		this.flags = flags
+		this.node  = node
+	}
+}
+
+class BuildSettings implements Serializable {
+	public final CC_Desc Compiler
+	public final Arch_Desc Architecture
+	public final Boolean RunAllTests
+	public final Boolean RunBenchmark
+	public final Boolean BuildDocumentation
+	public final Boolean Publish
+	public final Boolean Silent
+	public final Boolean IsSandbox
+	public final String DescLong
+	public final String DescShort
+
+	public String GitNewRef
+	public String GitOldRef
+
+	BuildSettings(java.util.Collections$UnmodifiableMap param, String branch) {
+		switch( param.Compiler ) {
+			case 'gcc-6':
+				this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6')
+			break
+			case 'gcc-5':
+				this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5')
+			break
+			case 'gcc-4.9':
+				this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9')
+			break
+			case 'clang':
+				this.Compiler = new CC_Desc('clang', 'clang++', 'gcc-6')
+			break
+			default :
+				error "Unhandled compiler : ${cc}"
+		}
+
+		switch( param.Architecture ) {
+			case 'x64':
+				this.Architecture = new Arch_Desc('x64', '--host=x86_64', 'x64')
+			break
+			case 'x86':
+				this.Architecture = new Arch_Desc('x86', '--host=i386', 'x86')
+			break
+			default :
+				error "Unhandled architecture : ${arch}"
+		}
+
+		this.IsSandbox          = (branch == "jenkins-sandbox")
+		this.RunAllTests        = param.RunAllTests
+		this.RunBenchmark       = param.RunBenchmark
+		this.BuildDocumentation = param.BuildDocumentation
+		this.Publish            = param.Publish
+		this.Silent             = param.Silent
+
+		def full = param.RunAllTests ? " (Full)" : ""
+		this.DescShort = "${ this.Compiler.name }:${ this.Architecture.name }${full}"
+
+		this.DescLong = """Compiler 	         : ${ this.Compiler.name } (${ this.Compiler.CXX }/${ this.Compiler.CC })
+Architecture            : ${ this.Architecture.name }
+Arc Flags               : ${ this.Architecture.flags }
+Run All Tests           : ${ this.RunAllTests.toString() }
+Run Benchmark           : ${ this.RunBenchmark.toString() }
+Build Documentation     : ${ this.BuildDocumentation.toString() }
+Publish                 : ${ this.Publish.toString() }
+Silent                  : ${ this.Silent.toString() }
+"""
+
+		this.GitNewRef = ''
+		this.GitOldRef = ''
+	}
+}
+
+class PlotGroup implements Serializable {
+	public String name
+	public String unit
+	public boolean log
+
+	PlotGroup(String name, String unit, boolean log) {
+		this.name = name
+		this.unit = unit
+		this.log = log
+	}
+}
+
+def prepare_build() {
+	// prepare the properties
+	properties ([ 													\
+		[$class: 'ParametersDefinitionProperty', 								\
+			parameterDefinitions: [ 									\
+				[$class: 'ChoiceParameterDefinition',						\
+					description: 'Which compiler to use',					\
+					name: 'Compiler',									\
+					choices: 'gcc-6\ngcc-5\ngcc-4.9\nclang',					\
+					defaultValue: 'gcc-6',								\
+				],												\
+				[$class: 'ChoiceParameterDefinition',						\
+					description: 'The target architecture',					\
+					name: 'Architecture',								\
+					choices: 'x64\nx86',								\
+					defaultValue: 'x64',								\
+				],												\
+				[$class: 'BooleanParameterDefinition',  						\
+					description: 'If false, only the quick test suite is ran', 		\
+					name: 'RunAllTests', 								\
+					defaultValue: false,  								\
+				], 												\
+				[$class: 'BooleanParameterDefinition',  						\
+					description: 'If true, jenkins also runs benchmarks', 		\
+					name: 'RunBenchmark', 								\
+					defaultValue: false,  								\
+				], 												\
+				[$class: 'BooleanParameterDefinition',  						\
+					description: 'If true, jenkins also builds documentation', 		\
+					name: 'BuildDocumentation', 							\
+					defaultValue: true,  								\
+				],												\
+				[$class: 'BooleanParameterDefinition',  						\
+					description: 'If true, jenkins also publishes results', 		\
+					name: 'Publish', 									\
+					defaultValue: false,  								\
+				],												\
+				[$class: 'BooleanParameterDefinition',  						\
+					description: 'If true, jenkins will not send emails', 		\
+					name: 'Silent', 									\
+					defaultValue: false,  								\
+				],												\
+			],
+		]])
+
+	// It's unfortunate but it looks like we need to checkout the entire repo just to get the pretty git printer
+	checkout scm
+
+	final settings = new BuildSettings(params, env.BRANCH_NAME)
+
+	currentBuild.description = settings.DescShort
+	echo                       settings.DescLong
+
+	return settings
+}
+
+def build_stage(String name, boolean run, Closure block ) {
+	StageName = name
+	echo " -------- ${StageName} -------- "
+	if(run) {
+		stage(name, block)
+	} else {
+		stage(name) { Utils.markStageSkippedForConditional(STAGE_NAME) }
+	}
+}
+
+def make_doc() {
+	def err = null
+	try {
+		sh 'make clean > /dev/null'
+		sh 'make > /dev/null 2>&1'
+	}
+	catch (Exception caughtError) {
+		err = caughtError //rethrow error later
+		sh 'cat build/*.log'
+	}
+	finally {
+		if (err) throw err // Must re-throw exception to propagate error
+	}
+}
+
+def do_plot(boolean new_data, String file, PlotGroup group, String title) {
+
+	if(new_data) {
+		echo "Publishing new data"
+	}
+
+	def series = new_data ? [[
+				file: "${file}.csv",
+				exclusionValues: '',
+				displayTableFlag: false,
+				inclusionFlag: 'OFF',
+				url: ''
+			]] : [];
+
+	echo "file is ${BuildDir}/benchmark/${file}.csv, group ${group}, title ${title}"
+	dir("${BuildDir}/benchmark/") {
+		plot csvFileName: "cforall-${env.BRANCH_NAME}-${file}.csv",
+			csvSeries: series,
+			group: "${group.name}",
+			title: "${title}",
+			style: 'lineSimple',
+			exclZero: false,
+			keepRecords: false,
+			logarithmic: group.log,
+			numBuilds: '120',
+			useDescr: true,
+			yaxis: group.unit,
+			yaxisMaximum: '',
+			yaxisMinimum: ''
+	}
+}
Index: src/AST/Attribute.hpp
===================================================================
--- src/AST/Attribute.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Attribute.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -51,4 +51,6 @@
 	template<typename node_t>
 	friend node_t * mutate(const node_t * node);
+	template<typename node_t>
+    friend node_t * shallowCopy(const node_t * node);
 };
 
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Convert.cpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -608,4 +608,15 @@
 
 		tgt->result = get<Type>().accept1(src->result);
+		// Unconditionally use a clone of the result type.
+		// We know this will leak some objects: much of the immediate conversion result.
+		// In some cases, using the conversion result directly gives unintended object sharing.
+		// A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache.
+		// But tgt->result must be fully owned privately by tgt.
+		// Applying these conservative copies here means
+		// - weak references point at the declaration's copy, not these expr.result copies (good)
+		// - we copy more objects than really needed (bad, tolerated)
+		if (tgt->result) {
+			tgt->result = tgt->result->clone();
+		}
 		return visitBaseExpr_skipResultType(src, tgt);
 	}
Index: src/AST/Copy.hpp
===================================================================
--- src/AST/Copy.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
+++ src/AST/Copy.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -0,0 +1,126 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Copy.hpp -- Provides functions to copy the AST.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Jul 10 16:13:00 2019
+// Last Modified By : Andrew Beach
+// Last Modified On : Thr Jul 11 10:38:00 2019
+// Update Count     : 0
+//
+
+#include "Decl.hpp"
+#include "Expr.hpp"
+#include "Pass.hpp"
+#include "Stmt.hpp"
+#include "Type.hpp"
+
+namespace ast {
+
+template<typename node_t>
+node_t * shallowCopy( const node_t * node );
+/* Create a shallow copy of the node given.
+ *
+ * The new node has all the same primitive field values and points to the
+ * same children nodes as the parent.
+ */
+
+template<typename node_t>
+node_t * deepCopy( const node_t * localRoot );
+/* Create a deep copy of the tree rooted at localRoot.
+ *
+ * This creates a copy of every node in the sub-tree (reachable by strong
+ * reference from local_root) and updates any readonly pointers on those nodes
+ * that point to another node in the sub-tree to the new version of that node.
+ */
+
+class DeepCopyCore {
+	std::unordered_map< const Node *, const Node * > nodeCache;
+	std::unordered_set< readonly<Node> * > readonlyCache;
+
+public:
+	template<typename node_t>
+	const node_t * previsit( const node_t * node ) {
+		const node_t * copy = shallowCopy( node );
+		nodeCache.insert( std::make_pair( node, copy ) );
+		return copy;
+	}
+
+	void postvisit( const AggregateDecl * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->parent );
+	}
+
+	void postvisit( const StructInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const UnionInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const EnumInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const TraitInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const TypeInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const ImplicitCtorDtorStmt * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->callStmt );
+	}
+
+	void postvisit( const MemberExpr * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->member );
+	}
+
+	void postvisit( const VariableExpr * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->var );
+	}
+
+	void postvisit( const OffsetofExpr * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->member );
+	}
+
+	void postvisit( const DeletedExpr * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->deleteStmt );
+	}
+
+	void readonlyUpdates() {
+		for ( readonly<Node> * ptr : readonlyCache ) {
+			auto it = nodeCache.find( ptr->get() );
+			if ( nodeCache.end() != it ) {
+				*ptr = it->second;
+			}
+		}
+	}
+};
+
+template<typename node_t>
+node_t * shallowCopy( const node_t * localRoot ) {
+	return localRoot->clone();
+}
+
+template<typename node_t>
+node_t * deepCopy( const node_t * localRoot ) {
+	Pass< DeepCopyCore > dc;
+	node_t const * newRoot = localRoot->accept( dc );
+	dc.pass.readonlyUpdates();
+	return const_cast< node_t * >( newRoot );
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Decl.cpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -52,5 +52,7 @@
 
 const Type * FunctionDecl::get_type() const { return type.get(); }
-void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); }
+void FunctionDecl::set_type( const Type * t ) {
+	type = strict_dynamic_cast< const FunctionType * >( t );
+}
 
 // --- TypeDecl
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Decl.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -32,5 +32,7 @@
 
 // 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);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
 
 namespace ast {
@@ -87,5 +89,5 @@
 	virtual const Type * get_type() const = 0;
 	/// Set type of this declaration. May be verified by subclass
-	virtual void set_type(Type *) = 0;
+	virtual void set_type( const Type * ) = 0;
 
 	const DeclWithType * accept( Visitor & v ) const override = 0;
@@ -110,5 +112,5 @@
 
 	const Type* get_type() const override { return type; }
-	void set_type( Type * ty ) override { type = ty; }
+	void set_type( const Type * ty ) override { type = ty; }
 
 	const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
@@ -132,5 +134,5 @@
 
 	const Type * get_type() const override;
-	void set_type(Type * t) override;
+	void set_type( const Type * t ) override;
 
 	bool has_body() const { return stmts; }
@@ -149,6 +151,7 @@
 	std::vector<ptr<DeclWithType>> assertions;
 
-	NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
-		Type* b, Linkage::Spec spec = Linkage::Cforall )
+	NamedTypeDecl( 
+		const CodeLocation & loc, const std::string & name, Storage::Classes storage,
+		const Type * b, Linkage::Spec spec = Linkage::Cforall )
 	: Decl( loc, name, storage, spec ), base( b ), params(), assertions() {}
 
@@ -185,6 +188,7 @@
 	};
 
-	TypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, Type* b,
-		TypeVar::Kind k, bool s, Type* i = nullptr )
+	TypeDecl( 
+		const CodeLocation & loc, const std::string & name, Storage::Classes storage, 
+		const Type * b, TypeVar::Kind k, bool s, const Type * i = nullptr )
 	: NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeVar::Ttype || s ),
 	  init( i ) {}
Index: src/AST/Eval.hpp
===================================================================
--- src/AST/Eval.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
+++ src/AST/Eval.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -0,0 +1,37 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Eval.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Fri Jun 28 14:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Created On       : Fri Jun 28 14:00:00 2019
+// Update Count     : 1
+//
+
+#include <string>
+#include <utility>
+
+#include "Expr.hpp"
+
+namespace ast {
+
+/// Create a new UntypedExpr with the given arguments
+template< typename... Args >
+UntypedExpr * call( const CodeLocation & loc, const std::string & name, Args &&... args ) {
+	return new UntypedExpr { 
+		loc, new NameExpr { loc, name }, 
+		std::vector< ptr< Expr > > { std::forward< Args >( args )... } };
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Expr.cpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -20,4 +20,5 @@
 #include <vector>
 
+#include "Eval.hpp"                // for call
 #include "GenericSubstitution.hpp"
 #include "Stmt.hpp"
@@ -51,7 +52,5 @@
 	assert( arg );
 
-	UntypedExpr * ret = new UntypedExpr{
-		loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
-	};
+	UntypedExpr * ret = call( loc, "*?", arg );
 	if ( const Type * ty = arg->result ) {
 		const Type * base = InitTweak::getPointerBase( ty );
@@ -74,7 +73,5 @@
 	assert( lhs && rhs );
 
-	UntypedExpr * ret = new UntypedExpr{
-		loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
-	};
+	UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
 	if ( lhs->result && rhs->result ) {
 		// if both expressions are typed, assumes that this assignment is a C bitwise assignment,
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Expr.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -30,5 +30,8 @@
 
 // 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);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
+
 
 class ConverterOldToNew;
Index: src/AST/ForallSubstitutionTable.cpp
===================================================================
--- src/AST/ForallSubstitutionTable.cpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
+++ src/AST/ForallSubstitutionTable.cpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -0,0 +1,54 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallSubstitutionTable.cpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Thu Jun 27 14:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Thu Jun 27 14:00:00 2019
+// Update Count     : 1
+//
+
+#include "ForallSubstitutionTable.hpp"
+
+#include <cassert>
+#include <vector>
+
+#include "Decl.hpp"
+#include "Node.hpp"
+#include "Type.hpp"
+#include "Visitor.hpp"
+
+namespace ast {
+
+std::vector< ptr< TypeDecl > > ForallSubstitutionTable::clone( 
+	const std::vector< ptr< TypeDecl > > & forall, Visitor & v 
+) {
+	std::vector< ptr< TypeDecl > > new_forall;
+	new_forall.reserve( forall.size() );
+
+	for ( const ast::TypeDecl * d : forall ) {
+		// create cloned type decl and insert into substitution map before further mutation
+		auto new_d = new ast::TypeDecl{
+			d->location, d->name, d->storage, d->base, d->kind, d->sized, d->init };
+		decls.insert( d, new_d );
+		// perform other mutations and add to output
+		auto newer_d = v.visit( new_d );
+		assert( new_d == newer_d && "Newly cloned TypeDecl must retain identity" );
+		new_forall.emplace_back( new_d );
+	}
+
+	return new_forall;
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/ForallSubstitutionTable.hpp
===================================================================
--- src/AST/ForallSubstitutionTable.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
+++ src/AST/ForallSubstitutionTable.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -0,0 +1,57 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallSubstitutionTable.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Thu Jun 27 14:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Thu Jun 27 14:00:00 2019
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <vector>
+
+#include "Node.hpp"  // for ptr
+#include "Common/ScopedMap.h"
+
+namespace ast {
+
+class TypeDecl;
+class Visitor;
+
+/// Wrapper for TypeDecl substitution table
+class ForallSubstitutionTable {
+	ScopedMap< const TypeDecl *, const TypeDecl * > decls;
+
+public:
+	/// Replaces given declaration with value in the table, if present, otherwise returns argument
+	const TypeDecl * replace( const TypeDecl * d ) {
+		auto it = decls.find( d );
+		if ( it != decls.end() ) return it->second;
+		return d;
+	}
+
+	/// Builds a new forall list mutated according to the given visitor
+	std::vector< ptr< TypeDecl > > clone( 
+		const std::vector< ptr< TypeDecl > > & forall, Visitor & v );
+
+	/// Introduces a new lexical scope
+	void beginScope() { decls.beginScope(); }
+
+	/// Concludes a lexical scope
+	void endScope() { decls.endScope(); }
+};
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/ForallSubstitutor.hpp
===================================================================
--- src/AST/ForallSubstitutor.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
+++ src/AST/ForallSubstitutor.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -0,0 +1,58 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallSubstitutor.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Wed Jun 26 15:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Wed Jun 26 15:00:00 2019
+// Update Count     : 1
+//
+
+#include "Pass.hpp"
+
+namespace ast {
+
+class Expr;
+
+/// Visitor that correctly substitutes TypeDecl while maintaining TypeInstType bindings.
+/// Also has some convenience methods to mutate fields.
+struct ForallSubstitutor : public WithForallSubstitutor, public WithVisitorRef<ForallSubstitutor> {
+	/// Substitute TypeInstType base type
+	readonly< TypeDecl > operator() ( const readonly< TypeDecl > & o ) {
+		return subs.replace( o );
+	}
+	
+	/// Make new forall-list clone
+	ParameterizedType::ForallList operator() ( const ParameterizedType::ForallList & o ) {
+		return subs.clone( o, *visitor );
+	}
+
+	/// Substitute parameter/return type
+	std::vector< ptr< DeclWithType > > operator() ( const std::vector< ptr< DeclWithType > > & o ) {
+		std::vector< ptr< DeclWithType > > n;
+		n.reserve( o.size() );
+		for ( const DeclWithType * d : o ) { n.emplace_back( d->accept( *visitor ) ); }
+		return n;
+	}
+
+	/// Substitute type parameter list
+	std::vector< ptr< Expr > > operator() ( const std::vector< ptr< Expr > > & o ) {
+		std::vector< ptr< Expr > > n;
+		n.reserve( o.size() );
+		for ( const Expr * d : o ) { n.emplace_back( d->accept( *visitor ) ); }
+		return n;
+	}
+};
+
+} // namespace ast
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Init.hpp
===================================================================
--- src/AST/Init.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Init.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -25,5 +25,7 @@
 
 // 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);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
 
 namespace ast {
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Node.cpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -17,4 +17,5 @@
 #include "Fwd.hpp"
 
+#include <csignal>  // MEMORY DEBUG -- for raise
 #include <iostream>
 
@@ -29,12 +30,33 @@
 #include "Print.hpp"
 
-template< typename node_t, enum ast::Node::ref_type ref_t >
-void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
-
-template< typename node_t, enum ast::Node::ref_type ref_t >
-void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
-
-template< typename node_t, enum ast::Node::ref_type ref_t >
-void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); }
+/// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object.
+/// Process to use in GDB:
+///   break ast::Node::_trap()
+///   run
+///   set variable MEM_TRAP_OBJ = <target>
+///   disable <first breakpoint>
+///   continue
+void * MEM_TRAP_OBJ = nullptr;
+
+void _trap( const void * node ) {
+	if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP);
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) {
+	node->increment(ref_t);
+	_trap( node );
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) {
+	_trap( node );
+	node->decrement(ref_t, do_delete );
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_check() const { 
+	// if(node) assert(node->was_ever_strong == false || node->strong_count > 0);
+}
 
 template< typename node_t, enum ast::Node::ref_type ref_t >
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Node.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -38,5 +38,5 @@
 	Node& operator= (const Node&) = delete;
 	Node& operator= (Node&&) = delete;
-	virtual ~Node() = default;
+	virtual ~Node() {}
 
 	virtual const Node * accept( Visitor & v ) const = 0;
@@ -57,4 +57,6 @@
 	template<typename node_t>
 	friend node_t * mutate(const node_t * node);
+	template<typename node_t>
+	friend node_t * shallowCopy(const node_t * node);
 
 	mutable size_t strong_count = 0;
@@ -69,5 +71,5 @@
 	}
 
-	void decrement(ast::Node::ref_type ref) const {
+	void decrement(ast::Node::ref_type ref, bool do_delete = true) const {
 		switch (ref) {
 			case ref_type::strong: strong_count--; break;
@@ -75,5 +77,5 @@
 		}
 
-		if(!strong_count && !weak_count) {
+		if( do_delete && !strong_count && !weak_count) {
 			delete this;
 		}
@@ -123,4 +125,13 @@
 	(ret->*field)[i] = std::forward< field_t >( val );
 	return ret;
+}
+
+/// Mutate an entire indexed collection by cloning to accepted value
+template<typename node_t, typename parent_t, typename coll_t>
+const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) {
+	for ( unsigned i = 0; i < (node->*field).size(); ++i ) {
+		node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) );
+	}
+	return node;
 }
 
@@ -219,4 +230,13 @@
 	operator const node_t * () const { _check(); return node; }
 
+	const node_t * release() {
+		const node_t * ret = node;
+		if ( node ) {
+			_dec(node, false);
+			node = nullptr;
+		}
+		return ret;
+	}
+
 	/// wrapper for convenient access to dynamic_cast
 	template<typename o_node_t>
@@ -244,5 +264,5 @@
 
 	void _inc( const node_t * other );
-	void _dec( const node_t * other );
+	void _dec( const node_t * other, bool do_delete = true );
 	void _check() const;
 
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Pass.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -35,4 +35,6 @@
 #include "AST/SymbolTable.hpp"
 
+#include "AST/ForallSubstitutionTable.hpp"
+
 // Private prelude header, needed for some of the magic tricks this class pulls off
 #include "AST/Pass.proto.hpp"
@@ -46,20 +48,21 @@
 //
 // Several additional features are available through inheritance
-// | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
-//                          current expression
-// | WithStmtsToAdd       - provides the ability to insert statements before or after the current
-//                          statement by adding new statements into stmtsToAddBefore or
-//                          stmtsToAddAfter respectively.
-// | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
-//                          declarations by adding new DeclStmt into declsToAddBefore or
-//                          declsToAddAfter respectively.
-// | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
-//                          to false in pre{visit,visit} to skip visiting children
-// | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save,
-//                          call GuardValue with the variable to save, the variable will
-//                          automatically be restored to its previous value after the corresponding
-//                          postvisit/postmutate teminates.
-// | WithVisitorRef       - provides an pointer to the templated visitor wrapper
-// | WithSymbolTable      - provides symbol table functionality
+// | WithTypeSubstitution  - provides polymorphic const TypeSubstitution * env for the
+//                           current expression
+// | WithStmtsToAdd        - provides the ability to insert statements before or after the current
+//                           statement by adding new statements into stmtsToAddBefore or
+//                           stmtsToAddAfter respectively.
+// | WithDeclsToAdd        - provides the ability to insert declarations before or after the
+//                           current declarations by adding new DeclStmt into declsToAddBefore or
+//                           declsToAddAfter respectively.
+// | WithShortCircuiting   - provides the ability to skip visiting child nodes; set visit_children
+//                           to false in pre{visit,visit} to skip visiting children
+// | WithGuards            - provides the ability to save/restore data like a LIFO stack; to save,
+//                           call GuardValue with the variable to save, the variable will
+//                           automatically be restored to its previous value after the
+//                           corresponding postvisit/postmutate teminates.
+// | WithVisitorRef        - provides an pointer to the templated visitor wrapper
+// | WithSymbolTable       - provides symbol table functionality
+// | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation
 //-------------------------------------------------------------------------------------------------
 template< typename pass_t >
@@ -201,4 +204,8 @@
 	container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
 
+	/// Mutate forall-list, accounting for presence of type substitution map
+	template<typename node_t>
+	void mutate_forall( const node_t *& );
+
 public:
 	/// Logic to call the accept and mutate the parent if needed, delegates call to accept
@@ -209,6 +216,6 @@
 	/// Internal RAII guard for symbol table features
 	struct guard_symtab {
-		guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }
-		~guard_symtab()                                   { __pass::symtab::leave(pass, 0); }
+		guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.pass, 0); }
+		~guard_symtab()                                   { __pass::symtab::leave(pass.pass, 0); }
 		Pass<pass_t> & pass;
 	};
@@ -216,7 +223,16 @@
 	/// Internal RAII guard for scope features
 	struct guard_scope {
-		guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
-		~guard_scope()                                   { __pass::scope::leave(pass, 0); }
+		guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass.pass, 0); }
+		~guard_scope()                                   { __pass::scope::leave(pass.pass, 0); }
 		Pass<pass_t> & pass;
+	};
+
+	/// Internal RAII guard for forall substitutions
+	struct guard_forall_subs {
+		guard_forall_subs( Pass<pass_t> & pass, const ParameterizedType * type )
+		: pass( pass ), type( type ) { __pass::forall::enter(pass.pass, 0, type ); }
+		~guard_forall_subs()         { __pass::forall::leave(pass.pass, 0, type ); }
+		Pass<pass_t> & pass;
+		const ParameterizedType * type;
 	};
 
@@ -313,4 +329,10 @@
 	SymbolTable symtab;
 };
+
+/// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl
+struct WithForallSubstitutor {
+	ForallSubstitutionTable subs;
+};
+
 }
 
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Pass.impl.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -127,8 +127,7 @@
 			, decltype( node->accept(*this) )
 		>::type
-
 	{
 		__pedantic_pass_assert( __visit_children() );
-		__pedantic_pass_assert( expr );
+		__pedantic_pass_assert( node );
 
 		static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
@@ -323,4 +322,20 @@
 	}
 
+
+	template< typename pass_t >
+	template< typename node_t >
+	void ast::Pass< pass_t >::mutate_forall( const node_t *& node ) {
+		if ( auto subs = __pass::forall::subs( pass, 0 ) ) {
+			// tracking TypeDecl substitution, full clone
+			if ( node->forall.empty() ) return;
+
+			node_t * mut = mutate( node );
+			mut->forall = subs->clone( node->forall, *this );
+			node = mut;
+		} else {
+			// not tracking TypeDecl substitution, just mutate
+			maybe_accept( node, &node_t::forall );
+		}
+	}
 }
 
@@ -429,12 +444,12 @@
 			guard_symtab guard { *this };
 			// implicit add __func__ identifier as specified in the C manual 6.4.2.2
-			static ast::ObjectDecl func(
-				node->location, "__func__",
-				new ast::ArrayType(
-					new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
+			static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{ 
+				CodeLocation{}, "__func__",
+				new ast::ArrayType{
+					new ast::BasicType{ ast::BasicType::Char, ast::CV::Const },
 					nullptr, VariableLen, DynamicDim
-				)
-			);
-			__pass::symtab::addId( pass, 0, &func );
+				}
+			} };
+			__pass::symtab::addId( pass, 0, func );
 			VISIT(
 				maybe_accept( node, &FunctionDecl::type );
@@ -610,8 +625,8 @@
 	VISIT({
 		// do not enter a new scope if inFunction is true - needs to check old state before the assignment
-		auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
-			if ( ! inFunction ) __pass::symtab::enter(pass, 0);
-		}, [this, inFunction = this->inFunction]() {
-			if ( ! inFunction ) __pass::symtab::leave(pass, 0);
+		auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() {
+			if ( ! inFunctionCpy ) __pass::symtab::enter(pass, 0);
+		}, [this, inFunctionCpy = this->inFunction]() {
+			if ( ! inFunctionCpy ) __pass::symtab::leave(pass, 0);
 		});
 		ValueGuard< bool > guard2( inFunction );
@@ -1667,9 +1682,10 @@
 	VISIT_START( node );
 
-	VISIT(
-		maybe_accept( node, &FunctionType::forall  );
+	VISIT({
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &FunctionType::returns );
 		maybe_accept( node, &FunctionType::params  );
-	)
+	})
 
 	VISIT_END( Type, node );
@@ -1686,5 +1702,6 @@
 	VISIT({
 		guard_symtab guard { *this };
-		maybe_accept( node, &StructInstType::forall );
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &StructInstType::params );
 	})
@@ -1699,11 +1716,12 @@
 	VISIT_START( node );
 
-	__pass::symtab::addStruct( pass, 0, node->name );
-
-	{
+	__pass::symtab::addUnion( pass, 0, node->name );
+
+	VISIT({
 		guard_symtab guard { *this };
-		maybe_accept( node, &UnionInstType::forall );
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &UnionInstType::params );
-	}
+	})
 
 	VISIT_END( Type, node );
@@ -1716,8 +1734,9 @@
 	VISIT_START( node );
 
-	VISIT(
-		maybe_accept( node, &EnumInstType::forall );
+	VISIT({
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &EnumInstType::params );
-	)
+	})
 
 	VISIT_END( Type, node );
@@ -1730,8 +1749,9 @@
 	VISIT_START( node );
 
-	VISIT(
-		maybe_accept( node, &TraitInstType::forall );
+	VISIT({
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &TraitInstType::params );
-	)
+	})
 
 	VISIT_END( Type, node );
@@ -1745,6 +1765,11 @@
 
 	VISIT(
-		maybe_accept( node, &TypeInstType::forall );
-		maybe_accept( node, &TypeInstType::params );
+		{
+			guard_forall_subs forall_guard { *this, node };
+			mutate_forall( node );
+			maybe_accept( node, &TypeInstType::params );
+		}
+		// ensure that base re-bound if doing substitution
+		__pass::forall::replace( pass, 0, node );
 	)
 
@@ -1895,5 +1920,5 @@
 				guard_symtab guard { *this };
 				auto new_node = p.second->accept( *this );
-				if (new_node != p.second) mutated = false;
+				if (new_node != p.second) mutated = true;
 				new_map.insert({ p.first, new_node });
 			}
@@ -1911,5 +1936,5 @@
 				guard_symtab guard { *this };
 				auto new_node = p.second->accept( *this );
-				if (new_node != p.second) mutated = false;
+				if (new_node != p.second) mutated = true;
 				new_map.insert({ p.first, new_node });
 			}
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Pass.proto.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -263,12 +263,12 @@
 		template<typename pass_t>
 		static inline void leave( pass_t &, long ) {}
-	};
-
-	// Finally certain pass desire an up to date symbol table automatically
+	} // namespace scope
+
+	// Certain passes desire an up to date symbol table automatically
 	// detect the presence of a member name `symtab` and call all the members appropriately
 	namespace symtab {
 		// Some simple scoping rules
 		template<typename pass_t>
-		static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {
+		static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab, void() ) {
 			pass.symtab.enterScope();
 		}
@@ -278,5 +278,5 @@
 
 		template<typename pass_t>
-		static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {
+		static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab, void() ) {
 			pass.symtab.leaveScope();
 		}
@@ -356,5 +356,49 @@
 		#undef SYMTAB_FUNC1
 		#undef SYMTAB_FUNC2
-	};
-};
-};
+	} // namespace symtab
+
+	// Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
+	// Detect the presence of a member name `subs` and call all members appropriately
+	namespace forall {
+		// Some simple scoping rules
+		template<typename pass_t>
+		static inline auto enter( pass_t & pass, int, const ast::ParameterizedType * type ) 
+		-> decltype( pass.subs, void() ) {
+			if ( ! type->forall.empty() ) pass.subs.beginScope();
+		}
+
+		template<typename pass_t>
+		static inline auto enter( pass_t &, long, const ast::ParameterizedType * ) {}
+
+		template<typename pass_t>
+		static inline auto leave( pass_t & pass, int, const ast::ParameterizedType * type ) 
+		-> decltype( pass.subs, void() ) {
+			if ( ! type->forall.empty() ) { pass.subs.endScope(); }
+		}
+
+		template<typename pass_t>
+		static inline auto leave( pass_t &, long, const ast::ParameterizedType * ) {}
+
+		// Get the substitution table, if present
+		template<typename pass_t>
+		static inline auto subs( pass_t & pass, int ) -> decltype( &pass.subs ) {
+			return &pass.subs;
+		}
+		
+		template<typename pass_t>
+		static inline ast::ForallSubstitutionTable * subs( pass_t &, long ) { return nullptr; }
+
+		// Replaces a TypeInstType's base TypeDecl according to the table
+		template<typename pass_t>
+		static inline auto replace( pass_t & pass, int, const ast::TypeInstType *& inst ) 
+		-> decltype( pass.subs, void() ) {
+			inst = ast::mutate_field( 
+				inst, &ast::TypeInstType::base, pass.subs.replace( inst->base ) );
+		}
+
+		template<typename pass_t>
+		static inline auto replace( pass_t &, long, const ast::TypeInstType *& ) {}
+
+	} // namespace forall
+} // namespace __pass
+} // namespace ast
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Stmt.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -27,5 +27,7 @@
 
 // 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);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
 
 namespace ast {
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Type.cpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -21,5 +21,7 @@
 
 #include "Decl.hpp"
+#include "ForallSubstitutor.hpp" // for substituteForall
 #include "Init.hpp"
+#include "Common/utility.h"      // for copy, move
 #include "InitTweak/InitTweak.h" // for getPointerBase
 #include "Tuples/Tuples.h"       // for isTtype
@@ -91,5 +93,22 @@
 );
 
+// --- ParameterizedType
+
+void ParameterizedType::initWithSub( 
+	const ParameterizedType & o, Pass< ForallSubstitutor > & sub 
+) {
+	forall = sub.pass( o.forall );
+}
+
 // --- FunctionType
+
+FunctionType::FunctionType( const FunctionType & o )
+: ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(), 
+  isVarArgs( o.isVarArgs ) {
+	Pass< ForallSubstitutor > sub;
+	initWithSub( o, sub );           // initialize substitution map
+	returns = sub.pass( o.returns ); // apply to return and parameter types
+	params = sub.pass( o.params );
+}
 
 namespace {
@@ -107,4 +126,17 @@
 
 // --- ReferenceToType
+
+void ReferenceToType::initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ) {
+	ParameterizedType::initWithSub( o, sub ); // initialize substitution
+	params = sub.pass( o.params );            // apply to parameters
+}
+
+ReferenceToType::ReferenceToType( const ReferenceToType & o )
+: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ), 
+  hoistType( o.hoistType ) {
+	Pass< ForallSubstitutor > sub;
+	initWithSub( o, sub );
+}
+
 std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const {
 	assertf( aggr(), "Must have aggregate to perform lookup" );
@@ -119,7 +151,7 @@
 // --- StructInstType
 
-StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+StructInstType::StructInstType( 
+	const StructDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
 
 bool StructInstType::isComplete() const { return base ? base->body : false; }
@@ -127,7 +159,7 @@
 // --- UnionInstType
 
-UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+UnionInstType::UnionInstType( 
+	const UnionDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
 
 bool UnionInstType::isComplete() const { return base ? base->body : false; }
@@ -135,7 +167,7 @@
 // --- EnumInstType
 
-EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+EnumInstType::EnumInstType( 
+	const EnumDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
 
 bool EnumInstType::isComplete() const { return base ? base->body : false; }
@@ -143,9 +175,16 @@
 // --- TraitInstType
 
-TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+TraitInstType::TraitInstType( 
+	const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
 
 // --- TypeInstType
+
+TypeInstType::TypeInstType( const TypeInstType & o ) 
+: ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) {
+	Pass< ForallSubstitutor > sub;
+	initWithSub( o, sub );      // initialize substitution
+	base = sub.pass( o.base );  // apply to base type
+}
 
 void TypeInstType::set_base( const TypeDecl * b ) {
@@ -159,5 +198,5 @@
 
 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
-: Type( q ), types( std::move(ts) ), members() {
+: Type( q ), types( move(ts) ), members() {
 	// This constructor is awkward. `TupleType` needs to contain objects so that members can be
 	// named, but members without initializer nodes end up getting constructors, which breaks
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/Type.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -30,7 +30,13 @@
 
 // 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);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
 
 namespace ast {
+
+template< typename T > class Pass;
+
+struct ForallSubstitutor;
 
 class Type : public Node {
@@ -164,5 +170,5 @@
 	static const char *typeNames[];
 
-	BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 
+	BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: Type(q, std::move(as)), kind(k) {}
 
@@ -266,4 +272,7 @@
 /// Base type for potentially forall-qualified types
 class ParameterizedType : public Type {
+protected:
+	/// initializes forall with substitutor
+	void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub );
 public:
 	using ForallList = std::vector<ptr<TypeDecl>>;
@@ -277,4 +286,11 @@
 	ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
 	: Type(q, std::move(as)), forall() {}
+
+	// enforce use of ForallSubstitutor to copy parameterized type
+	ParameterizedType( const ParameterizedType & ) = delete;
+
+	ParameterizedType( ParameterizedType && ) = default;
+
+	// no need to change destructor, and operator= deleted in Node
 
 private:
@@ -302,4 +318,6 @@
 	: ParameterizedType(q), returns(), params(), isVarArgs(va) {}
 
+	FunctionType( const FunctionType & o );
+
 	/// true if either the parameters or return values contain a tttype
 	bool isTtype() const;
@@ -315,4 +333,7 @@
 /// base class for types that refer to types declared elsewhere (aggregates and typedefs)
 class ReferenceToType : public ParameterizedType {
+protected:
+	/// Initializes forall and parameters based on substitutor
+	void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub );
 public:
 	std::vector<ptr<Expr>> params;
@@ -320,7 +341,9 @@
 	bool hoistType = false;
 
-	ReferenceToType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	ReferenceToType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ParameterizedType(q, std::move(as)), params(), name(n) {}
+
+	ReferenceToType( const ReferenceToType & o );
 
 	/// Gets aggregate declaration this type refers to
@@ -339,9 +362,10 @@
 	readonly<StructDecl> base;
 
-	StructInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	StructInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	StructInstType( const StructDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	StructInstType(
+		const StructDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	bool isComplete() const override;
@@ -360,9 +384,10 @@
 	readonly<UnionDecl> base;
 
-	UnionInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	UnionInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	UnionInstType( const UnionDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	UnionInstType(
+		const UnionDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	bool isComplete() const override;
@@ -381,9 +406,10 @@
 	readonly<EnumDecl> base;
 
-	EnumInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	EnumInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	EnumInstType( const EnumDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	EnumInstType(
+		const EnumDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	bool isComplete() const override;
@@ -402,9 +428,10 @@
 	readonly<TraitDecl> base;
 
-	TraitInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	TraitInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	TraitInstType( const TraitDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	TraitInstType(
+		const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	// not meaningful for TraitInstType
@@ -425,10 +452,15 @@
 	TypeVar::Kind kind;
 
-	TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
+	TypeInstType(
+		const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
 		std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
-	TypeInstType( const std::string& n, TypeVar::Kind k, CV::Qualifiers q = {},
+
+	TypeInstType(
+		const std::string& n, TypeVar::Kind k, CV::Qualifiers q = {},
 		std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
+
+	TypeInstType( const TypeInstType & o );
 
 	/// sets `base`, updating `kind` correctly
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/TypeSubstitution.cpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -92,5 +92,5 @@
 namespace {
 	struct EnvTrimmer {
-		ptr<TypeSubstitution> env;
+		const TypeSubstitution * env;
 		TypeSubstitution * newEnv;
 		EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
@@ -108,11 +108,6 @@
 	if ( env ) {
 		TypeSubstitution * newEnv = new TypeSubstitution();
-#if TIME_TO_CONVERT_PASSES
 		Pass<EnvTrimmer> trimmer( env, newEnv );
 		expr->accept( trimmer );
-#else
-		(void)expr;
-		(void)env;
-#endif
 		return newEnv;
 	}
@@ -121,19 +116,15 @@
 
 void TypeSubstitution::normalize() {
-#if TIME_TO_CONVERT_PASSES
-	PassVisitor<Substituter> sub( *this, true );
+	Pass<Substituter> sub( *this, true );
 	do {
 		sub.pass.subCount = 0;
 		sub.pass.freeOnly = true;
 		for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
-			i->second = i->second->acceptMutator( sub );
+			i->second = i->second->accept( sub );
 		}
 	} while ( sub.pass.subCount );
-#endif
-}
-
-#if TIME_TO_CONVERT_PASSES
-
-Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
+}
+
+const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
 	BoundVarsType::const_iterator bound = boundVars.find( inst->name );
 	if ( bound != boundVars.end() ) return inst;
@@ -146,5 +137,5 @@
 		// Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here.
 		// TODO: investigate preventing type variables from being bound to themselves in the first place.
-		if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {
+		if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
 			if ( inst->name == replacement->name ) {
 				return inst;
@@ -153,13 +144,14 @@
 		// std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl;
 		subCount++;
-		Type * newtype = i->second->clone();
-		newtype->get_qualifiers() |= inst->get_qualifiers();
-		delete inst;
-		// Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
-		return newtype->acceptMutator( *visitor );
-	} // if
-}
-
-Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) {
+		ptr<Type> newType = i->second; // force clone if needed
+		add_qualifiers( newType, inst->qualifiers );
+		// Note: need to recursively apply substitution to the new type because normalize does not 
+		// substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
+		newType = newType->accept( *visitor );
+		return newType.release();
+	} // if
+}
+
+const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
 	VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
 	if ( i == sub.varEnv.end() ) {
@@ -168,45 +160,43 @@
 		subCount++;
 		delete nameExpr;
-		return i->second->clone();
-	} // if
-}
-
-void TypeSubstitution::Substituter::premutate( Type * type ) {
+		return i->second;
+	} // if
+}
+
+void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
-			boundVars.insert( (*tyvar)->name );
+		for ( const TypeDecl * tyvar : ptype->forall ) {
+				boundVars.insert( tyvar->name );
 		} // for
 	} // if
 }
 
-template< typename TypeClass >
-void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) {
+void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
-			boundVars.insert( (*tyvar)->name );
+		for ( const TypeDecl * tyvar : type->forall ) {
+			boundVars.insert( tyvar->name );
 		} // for
 		// bind type variables from generic type instantiations
-		std::list< TypeDecl* > *baseParameters = type->get_baseParameters();
-		if ( baseParameters && ! type->parameters.empty() ) {
-			for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) {
-				boundVars.insert( (*tyvar)->name );
-			} // for
-		} // if
-	} // if
-}
-
-void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) {
+		if ( auto decl = type->aggr() ) {
+			if ( ! type->params.empty() ) {
+				for ( const TypeDecl * tyvar : decl->params ) {
+					boundVars.insert( tyvar->name );
+				} // for
+			} // if
+		}
+	} // if
+}
+
+void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) {
 	handleAggregateType( aggregateUseType );
 }
 
-void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
+void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) {
 	handleAggregateType( aggregateUseType );
 }
-
-#endif
 
 } // namespace ast
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/TypeSubstitution.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -155,18 +155,14 @@
 		Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
 
-#if TIME_TO_CONVERT_PASSES
-
-		Type * postmutate( TypeInstType * aggregateUseType );
-		Expression * postmutate( NameExpr * nameExpr );
+		const Type * postvisit( const TypeInstType * aggregateUseType );
+		const Expr * postvisit( const NameExpr * nameExpr );
 
 		/// Records type variable bindings from forall-statements
-		void premutate( Type * type );
+		void previsit( const ParameterizedType * type );
 		/// Records type variable bindings from forall-statements and instantiations of generic types
-		template< typename TypeClass > void handleAggregateType( TypeClass * type );
-
-		void premutate( StructInstType * aggregateUseType );
-		void premutate( UnionInstType * aggregateUseType );
-
-#endif
+		void handleAggregateType( const ReferenceToType * type );
+
+		void previsit( const StructInstType * aggregateUseType );
+		void previsit( const UnionInstType * aggregateUseType );
 
 		const TypeSubstitution & sub;
Index: src/AST/module.mk
===================================================================
--- src/AST/module.mk	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/AST/module.mk	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -22,4 +22,5 @@
 	AST/DeclReplacer.cpp \
 	AST/Expr.cpp \
+	AST/ForallSubstitutionTable.cpp \
 	AST/GenericSubstitution.cpp \
 	AST/Init.cpp \
Index: src/Common/ScopedMap.h
===================================================================
--- src/Common/ScopedMap.h	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/Common/ScopedMap.h	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -249,4 +249,6 @@
 
 	/// Gets the note at the given scope
+	Note& getNote() { return scopes.back().note; }
+	const Note& getNote() const { return scopes.back().note; }
 	Note& getNote( size_type i ) { return scopes[i].note; }
 	const Note& getNote( size_type i ) const { return scopes[i].note; }
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/Makefile.in	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -168,4 +168,5 @@
 	AST/Convert.$(OBJEXT) AST/Decl.$(OBJEXT) \
 	AST/DeclReplacer.$(OBJEXT) AST/Expr.$(OBJEXT) \
+	AST/ForallSubstitutionTable.$(OBJEXT) \
 	AST/GenericSubstitution.$(OBJEXT) AST/Init.$(OBJEXT) \
 	AST/LinkageSpec.$(OBJEXT) AST/Node.$(OBJEXT) \
@@ -585,4 +586,5 @@
 	AST/DeclReplacer.cpp \
 	AST/Expr.cpp \
+	AST/ForallSubstitutionTable.cpp \
 	AST/GenericSubstitution.cpp \
 	AST/Init.cpp \
@@ -759,4 +761,6 @@
 	AST/$(DEPDIR)/$(am__dirstamp)
 AST/Expr.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp)
+AST/ForallSubstitutionTable.$(OBJEXT): AST/$(am__dirstamp) \
+	AST/$(DEPDIR)/$(am__dirstamp)
 AST/GenericSubstitution.$(OBJEXT): AST/$(am__dirstamp) \
 	AST/$(DEPDIR)/$(am__dirstamp)
@@ -1212,4 +1216,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/DeclReplacer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Expr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/ForallSubstitutionTable.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/GenericSubstitution.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Init.Po@am__quote@
Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/AdjustExprType.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -100,35 +100,36 @@
 
 namespace {
-	struct AdjustExprType_new final : public ast::WithShortCircuiting {
+	class AdjustExprType_new final : public ast::WithShortCircuiting {
+		const ast::SymbolTable & symtab;
+	public:
 		const ast::TypeEnvironment & tenv;
-		const ast::SymbolTable & symtab;
 
 		AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
-		: tenv( e ), symtab( syms ) {}
+		: symtab( syms ), tenv( e ) {}
 
-		void premutate( const ast::VoidType * ) { visit_children = false; }
-		void premutate( const ast::BasicType * ) { visit_children = false; }
-		void premutate( const ast::PointerType * ) { visit_children = false; }
-		void premutate( const ast::ArrayType * ) { visit_children = false; }
-		void premutate( const ast::FunctionType * ) { visit_children = false; }
-		void premutate( const ast::StructInstType * ) { visit_children = false; }
-		void premutate( const ast::UnionInstType * ) { visit_children = false; }
-		void premutate( const ast::EnumInstType * ) { visit_children = false; }
-		void premutate( const ast::TraitInstType * ) { visit_children = false; }
-		void premutate( const ast::TypeInstType * ) { visit_children = false; }
-		void premutate( const ast::TupleType * ) { visit_children = false; }
-		void premutate( const ast::VarArgsType * ) { visit_children = false; }
-		void premutate( const ast::ZeroType * ) { visit_children = false; }
-		void premutate( const ast::OneType * ) { visit_children = false; }
+		void previsit( const ast::VoidType * ) { visit_children = false; }
+		void previsit( const ast::BasicType * ) { visit_children = false; }
+		void previsit( const ast::PointerType * ) { visit_children = false; }
+		void previsit( const ast::ArrayType * ) { visit_children = false; }
+		void previsit( const ast::FunctionType * ) { visit_children = false; }
+		void previsit( const ast::StructInstType * ) { visit_children = false; }
+		void previsit( const ast::UnionInstType * ) { visit_children = false; }
+		void previsit( const ast::EnumInstType * ) { visit_children = false; }
+		void previsit( const ast::TraitInstType * ) { visit_children = false; }
+		void previsit( const ast::TypeInstType * ) { visit_children = false; }
+		void previsit( const ast::TupleType * ) { visit_children = false; }
+		void previsit( const ast::VarArgsType * ) { visit_children = false; }
+		void previsit( const ast::ZeroType * ) { visit_children = false; }
+		void previsit( const ast::OneType * ) { visit_children = false; }
 
-		const ast::Type * postmutate( const ast::ArrayType * at ) {
+		const ast::Type * postvisit( const ast::ArrayType * at ) {
 			return new ast::PointerType{ at->base, at->qualifiers };
 		}
 
-		const ast::Type * postmutate( const ast::FunctionType * ft ) {
+		const ast::Type * postvisit( const ast::FunctionType * ft ) {
 			return new ast::PointerType{ ft };
 		}
 
-		const ast::Type * postmutate( const ast::TypeInstType * inst ) {
+		const ast::Type * postvisit( const ast::TypeInstType * inst ) {
 			// replace known function-type-variables with pointer-to-function
 			if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -370,7 +370,5 @@
 							// push empty tuple expression
 							newResult.parent = i;
-							std::vector< ast::ptr< ast::Expr > > emptyList;
-							newResult.expr = 
-								new ast::TupleExpr{ CodeLocation{}, move( emptyList ) };
+							newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
 							argType = newResult.expr->result;
 						} else {
@@ -548,5 +546,5 @@
 		genStart = genEnd;
 
-		return genEnd != results.size();
+		return genEnd != results.size();  // were any new results added?
 	}
 
@@ -594,7 +592,8 @@
 
 	/// Actually visits expressions to find their candidate interpretations
-	struct Finder final : public ast::WithShortCircuiting {
+	class Finder final : public ast::WithShortCircuiting {
+		const ast::SymbolTable & symtab;
+	public:
 		CandidateFinder & selfFinder;
-		const ast::SymbolTable & symtab;
 		CandidateList & candidates;
 		const ast::TypeEnvironment & tenv;
@@ -602,5 +601,5 @@
 
 		Finder( CandidateFinder & f )
-		: selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ), 
+		: symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 
 		  targetType( f.targetType ) {}
 		
@@ -676,6 +675,6 @@
 			ast::TypeEnvironment funcEnv{ func->env };
 			makeUnifiableVars( funcType, funcOpen, funcNeed );
-			// add all type variables as open variables now so that those not used in the parameter 
-			// list are still considered open
+			// add all type variables as open variables now so that those not used in the 
+			// parameter list are still considered open
 			funcEnv.add( funcType->forall );
 
@@ -1558,5 +1557,5 @@
 		std::vector< std::string > errors;
 		for ( CandidateRef & candidate : candidates ) {
-			satisfyAssertions( candidate, symtab, satisfied, errors );
+			satisfyAssertions( candidate, localSyms, satisfied, errors );
 		}
 
@@ -1613,5 +1612,5 @@
 			r->expr = ast::mutate_field( 
 				r->expr.get(), &ast::Expr::result, 
-				adjustExprType( r->expr->result, r->env, symtab ) );
+				adjustExprType( r->expr->result, r->env, localSyms ) );
 		}
 	}
@@ -1631,5 +1630,5 @@
 
 	for ( const auto & x : xs ) {
-		out.emplace_back( symtab, env );
+		out.emplace_back( localSyms, env );
 		out.back().find( x, ResolvMode::withAdjustment() );
 		
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -28,12 +28,12 @@
 struct CandidateFinder {
 	CandidateList candidates;          ///< List of candidate resolutions
-	const ast::SymbolTable & symtab;   ///< Symbol table to lookup candidates
+	const ast::SymbolTable & localSyms;   ///< Symbol table to lookup candidates
 	const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
 	ast::ptr< ast::Type > targetType;  ///< Target type for resolution
 
 	CandidateFinder( 
-		const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 
+		const ast::SymbolTable & syms, const ast::TypeEnvironment & env, 
 		const ast::Type * tt = nullptr )
-	: candidates(), symtab( symtab ), env( env ), targetType( tt ) {}
+	: candidates(), localSyms( syms ), env( env ), targetType( tt ) {}
 
 	/// Fill candidates with feasible resolutions for `expr`
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/CommonType.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -939,5 +939,5 @@
 			ast::ptr< ast::Type > result;
 			const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >();
-			const ast::ReferenceType * ref2 = type1.as< ast::ReferenceType >();
+			const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >();
 
 			if ( depth1 > depth2 ) {
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/ConversionCost.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -10,6 +10,6 @@
 // Created On       : Sun May 17 07:06:19 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Mon Jun 24 13:33:00 2019
-// Update Count     : 26
+// Last Modified On : Thr Jul  4 10:56:00 2019
+// Update Count     : 27
 //
 
@@ -764,4 +764,8 @@
 			cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
 		}
+	} else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
+		cost = Cost::zero;
+		// +1 for zero_t ->, +1 for disambiguation
+		cost.incSafe( maxIntCost + 2 );
 	}
 }
@@ -781,7 +785,4 @@
 			cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
 		}
-	} else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
-		cost = Cost::zero;
-		cost.incSafe( maxIntCost + 2 );
 	}
 }
Index: src/ResolvExpr/PolyCost.cc
===================================================================
--- src/ResolvExpr/PolyCost.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/PolyCost.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -58,11 +58,12 @@
 
 // TODO: When the old PolyCost is torn out get rid of the _new suffix.
-struct PolyCost_new {
+class PolyCost_new {
+	const ast::SymbolTable &symtab;
+public:
 	int result;
-	const ast::SymbolTable &symtab;
 	const ast::TypeEnvironment &env_;
 
-	PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :
-		result( 0 ), symtab( symtab ), env_( env ) {}
+	PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 
+	: symtab( symtab ), result( 0 ), env_( env ) {}
 
 	void previsit( const ast::TypeInstType * type ) {
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/RenameVars.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -19,4 +19,5 @@
 #include <utility>                 // for pair
 
+#include "AST/ForallSubstitutionTable.hpp"
 #include "AST/Pass.hpp"
 #include "AST/Type.hpp"
@@ -30,4 +31,6 @@
 #include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
 
+#include "AST/Copy.hpp"
+
 namespace ResolvExpr {
 
@@ -37,6 +40,7 @@
 		int resetCount = 0;
 		ScopedMap< std::string, std::string > nameMap;
+	public:
+		ast::ForallSubstitutionTable subs;
 
-	public:
 		void reset() {
 			level = 0;
@@ -44,8 +48,6 @@
 		}
 
-		using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;
-
 		void rename( TypeInstType * type ) {
-			mapConstIterator it = nameMap.find( type->name );
+			auto it = nameMap.find( type->name );
 			if ( it != nameMap.end() ) {
 				type->name = it->second;
@@ -65,7 +67,6 @@
 					// ditto for assertion names, the next level in
 					level++;
-					// acceptAll( td->assertions, *this );
-				} // for
-			} // if
+				}
+			}
 		}
 
@@ -77,10 +78,16 @@
 
 		const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
-			mapConstIterator it = nameMap.find( type->name );
+			// re-linking of base type handled by WithForallSubstitutor
+
+			// rename
+			auto it = nameMap.find( type->name );
 			if ( it != nameMap.end() ) {
-				ast::TypeInstType * mutType = ast::mutate( type );
-				mutType->name = it->second;
-	            type = mutType;
+				// unconditionally mutate because map will *always* have different name, 
+				// if this mutates, will *always* have been mutated by ForallSubstitutor above
+				ast::TypeInstType * mut = ast::mutate( type );
+				mut->name = it->second;
+	            type = mut;
 			}
+
 			return type;
 		}
@@ -88,29 +95,32 @@
 		template<typename NodeT>
 		const NodeT * openLevel( const NodeT * type ) {
-			if ( !type->forall.empty() ) {
-				nameMap.beginScope();
-				// Load new names from this forall clause and perform renaming.
-				NodeT * mutType = ast::mutate( type );
-				for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
-					std::ostringstream output;
-					output << "_" << resetCount << "_" << level << "_" << td->name;
-					std::string newname( output.str() );
-					nameMap[ td->name ] = newname;
-					++level;
+			if ( type->forall.empty() ) return type;
+			
+			nameMap.beginScope();
 
-					ast::TypeDecl * decl = ast::mutate( td.get() );
-					decl->name = newname;
-					td = decl;
-				}
+			// Load new names from this forall clause and perform renaming.
+			NodeT * mutType = ast::mutate( type );
+			assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
+			for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
+				std::ostringstream output;
+				output << "_" << resetCount << "_" << level << "_" << td->name;
+				std::string newname =  output.str();
+				nameMap[ td->name ] = newname;
+				++level;
+
+				ast::TypeDecl * mutDecl = ast::mutate( td.get() );
+				assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
+				mutDecl->name = newname;
+				// assertion above means `td = mutDecl;` is unnecessary
 			}
+			// assertion above means `type = mutType;` is unnecessary
+
 			return type;
 		}
 
-		template<typename NodeT>
-		const NodeT * closeLevel( const NodeT * type ) {
-			if ( !type->forall.empty() ) {
-				nameMap.endScope();
-			}
-			return type;
+		void closeLevel( const ast::ParameterizedType * type ) {
+			if ( type->forall.empty() ) return;
+			
+			nameMap.endScope();
 		}
 	};
@@ -119,5 +129,5 @@
 	RenamingData renaming;
 
-	struct RenameVars {
+	struct RenameVars_old {
 		void previsit( TypeInstType * instType ) {
 			renaming.openLevel( (Type*)instType );
@@ -130,4 +140,9 @@
 			renaming.closeLevel( type );
 		}
+	};
+	
+	struct RenameVars_new /*: public ast::WithForallSubstitutor*/ {
+		#warning when old RenameVars goes away, replace hack below with global pass inheriting from WithForallSubstitutor
+		ast::ForallSubstitutionTable & subs = renaming.subs;
 
 		const ast::FunctionType * previsit( const ast::FunctionType * type ) {
@@ -146,6 +161,6 @@
 			return renaming.rename( renaming.openLevel( type ) );
 		}
-		const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) {
-			return renaming.closeLevel( type );
+		void postvisit( const ast::ParameterizedType * type ) {
+			renaming.closeLevel( type );
 		}
 	};
@@ -154,11 +169,13 @@
 
 void renameTyVars( Type * t ) {
-	PassVisitor<RenameVars> renamer;
+	PassVisitor<RenameVars_old> renamer;
 	t->accept( renamer );
 }
 
 const ast::Type * renameTyVars( const ast::Type * t ) {
-	ast::Pass<RenameVars> renamer;
-	return t->accept( renamer );
+	ast::Type *tc = ast::deepCopy(t);
+	ast::Pass<RenameVars_new> renamer;
+//	return t->accept( renamer );
+	return tc->accept( renamer );
 }
 
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -153,5 +153,5 @@
 			}
 
-			return newType;
+			return newType.release();
 		}
 	};
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/Resolver.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -1108,5 +1108,5 @@
 
 		// set up and resolve expression cast to void
-		ast::CastExpr * untyped = new ast::CastExpr{ expr };
+		ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
 		CandidateRef choice = findUnfinishedKindExpression(
 			untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
@@ -1247,5 +1247,5 @@
 	};
 
-	void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) {
+	void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) {
 		ast::Pass< Resolver_new > resolver;
 		accept_all( translationUnit, resolver );
@@ -1281,5 +1281,5 @@
 		ast::ptr< ast::FunctionDecl > ret = functionDecl;
 		for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {
-			const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i];
+			const ast::ptr< ast::DeclWithType > & d = functionDecl->type->params[i];
 
 			if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {
@@ -1298,5 +1298,5 @@
 			}
 		}
-		return ret.get();
+		return ret.release();
 	}
 
Index: src/ResolvExpr/SpecCost.cc
===================================================================
--- src/ResolvExpr/SpecCost.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/ResolvExpr/SpecCost.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -10,8 +10,9 @@
 // Created On       : Tue Oct 02 15:50:00 2018
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Jun 19 10:43:00 2019
-// Update Count     : 2
-//
-
+// Last Modified On : Wed Jul  3 11:07:00 2019
+// Update Count     : 3
+//
+
+#include <cassert>
 #include <limits>
 #include <list>
@@ -129,4 +130,12 @@
 			typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
 
+		#warning Should use a standard maybe_accept
+		void maybe_accept( ast::Type const * type ) {
+			if ( type ) {
+				auto node = type->accept( *visitor );
+				assert( node == nullptr || node == type );
+			}
+		}
+
 		// Update the minimum to the new lowest non-none value.
 		template<typename T>
@@ -134,5 +143,5 @@
 			for ( const auto & node : list ) {
 				count = -1;
-				mapper( node )->accept( *visitor );
+				maybe_accept( mapper( node ) );
 				if ( count != -1 && count < minimum ) minimum = count;
 			}
Index: src/SymTab/Autogen.h
===================================================================
--- src/SymTab/Autogen.h	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/SymTab/Autogen.h	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -21,4 +21,5 @@
 
 #include "AST/Decl.hpp"
+#include "AST/Eval.hpp"
 #include "AST/Expr.hpp"
 #include "AST/Init.hpp"
@@ -264,5 +265,6 @@
 		}
 
-		ast::ptr< ast::Expr > begin, end, cmp, update;
+		ast::ptr< ast::Expr > begin, end;
+		std::string cmp, update;
 
 		if ( forward ) {
@@ -270,14 +272,13 @@
 			begin = ast::ConstantExpr::from_int( loc, 0 );
 			end = array->dimension;
-			cmp = new ast::NameExpr{ loc, "?<?" };
-			update = new ast::NameExpr{ loc, "++?" };
+			cmp = "?<?";
+			update = "++?";
 		} else {
 			// generate: for ( int i = N-1; i >= 0; --i )
-			begin = new ast::UntypedExpr{ 
-				loc, new ast::NameExpr{ loc, "?-?" }, 
-				{ array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } };
+			begin = ast::call( 
+				loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
 			end = ast::ConstantExpr::from_int( loc, 0 );
-			cmp = new ast::NameExpr{ loc, "?>=?" };
-			update = new ast::NameExpr{ loc, "--?" };
+			cmp = "?>=?";
+			update = "--?";
 		}
 
@@ -285,18 +286,15 @@
 			loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 
 			new ast::SingleInit{ loc, begin } };
-		
-		ast::ptr< ast::Expr > cond = new ast::UntypedExpr{
-			loc, cmp, { new ast::VariableExpr{ loc, index }, end } };
-		
-		ast::ptr< ast::Expr > inc = new ast::UntypedExpr{
-			loc, update, { new ast::VariableExpr{ loc, index } } };
-		
-		ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{
-			loc, new ast::NameExpr{ loc, "?[?]" }, 
-			{ dstParam, new ast::VariableExpr{ loc, index } } };
+		ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
+		
+		ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
+		
+		ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
+		
+		ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
 		
 		// srcParam must keep track of the array indices to build the source parameter and/or 
 		// array list initializer
-		srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );
+		srcParam.addArrayIndex( indexVar, array->dimension );
 
 		// for stmt's body, eventually containing call
@@ -384,5 +382,5 @@
 		if ( isUnnamedBitfield( obj ) ) return {};
 
-		ast::ptr< ast::Type > addCast = nullptr;
+		ast::ptr< ast::Type > addCast;
 		if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
 			assert( dstParam->result );
Index: src/Tuples/Explode.cc
===================================================================
--- src/Tuples/Explode.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/Tuples/Explode.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -129,5 +129,4 @@
 			for ( const ast::Expr * expr : tupleExpr->exprs ) {
 				exprs.emplace_back( applyCast( expr, false ) );
-				//exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );
 			}
 			if ( first ) {
Index: src/Tuples/Explode.h
===================================================================
--- src/Tuples/Explode.h	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/Tuples/Explode.h	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -210,5 +210,5 @@
 			}
 			// Cast a reference away to a value-type to allow further explosion.
-			if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) {
+			if ( local->result.as< ast::ReferenceType >() ) {
 				local = new ast::CastExpr{ local, tupleType };
 			}
@@ -220,5 +220,4 @@
 				// delete idx;
 			}
-			// delete local;
 		}
 	} else {
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/Tuples/TupleAssignment.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -465,5 +465,5 @@
 					// resolve ctor/dtor for the new object
 					ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
-							InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab );
+							InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms );
 					// remove environments from subexpressions of stmtExpr
 					ast::Pass< EnvRemover > rm{ env };
@@ -560,5 +560,5 @@
 					// resolve the cast expression so that rhsCand return type is bound by the cast
 					// type as needed, and transfer the resulting environment
-					ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env };
+					ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env };
 					finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
 					assert( finder.candidates.size() == 1 );
@@ -609,5 +609,5 @@
 					// explode the LHS so that each field of a tuple-valued expr is assigned
 					ResolvExpr::CandidateList lhs;
-					explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true );
+					explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true );
 					for ( ResolvExpr::CandidateRef & cand : lhs ) {
 						// each LHS value must be a reference - some come in with a cast, if not
@@ -629,5 +629,5 @@
 							if ( isTuple( rhsCand->expr ) ) {
 								// multiple assignment
-								explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true );
+								explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
 								matcher.reset(
 									new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
@@ -648,5 +648,5 @@
 							// multiple assignment
 							ResolvExpr::CandidateList rhs;
-							explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true );
+							explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
 							matcher.reset(
 								new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
@@ -678,5 +678,5 @@
 				)
 
-				ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env };
+				ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env };
 
 				try {
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 83b52f10c32ca12f8f96a9532884e06dd2d083dd)
+++ src/main.cc	(revision 96ac72c02fbef1f5ea479906ac9e2c82cfc53309)
@@ -29,4 +29,5 @@
 #include <string>                           // for char_traits, operator<<
 
+#include "AST/Convert.hpp"
 #include "CompilationState.h"
 #include "../config.h"                      // for CFA_LIBDIR
@@ -302,5 +303,10 @@
 		} // if
 
-		PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
+		// PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
+		{
+			auto transUnit = convert( move( translationUnit ) );
+			PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
+			translationUnit = convert( move( transUnit ) );
+		}
 		if ( exprp ) {
 			dump( translationUnit );
