Index: Jenkins/FullBuild
===================================================================
--- Jenkins/FullBuild	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ Jenkins/FullBuild	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -8,4 +8,7 @@
 	def err = null
 
+	final scmVars = checkout scm
+	final commitId = scmVars.GIT_COMMIT
+
 	try {
 		//Wrap build to add timestamp to command line
@@ -13,6 +16,4 @@
 
 			stage('Build') {
-
-				results = [null, null]
 
 				parallel (
@@ -31,5 +32,5 @@
 
 			stage('Package') {
-				build job: 'Cforall_Distribute_Ref', parameters: [string(name: 'GitRef', value: gitRefNewValue), string(name: 'Build', value: currentBuild.number)]
+				build job: 'Cforall_Distribute_Ref', parameters: [string(name: 'GitRef', value: commitId), string(name: 'Build', value: currentBuild.number.toString())]
 			}
 		}
@@ -102,20 +103,4 @@
 }
 
-//Helper routine to collect information about the git history
-def collect_git_info() {
-
-	//create the temporary output directory in case it doesn't already exist
-	def out_dir = pwd tmp: true
-	sh "mkdir -p ${out_dir}"
-
-	//parse git logs to find what changed
-	dir("../Cforall_Full_Build@script") {
-		sh "git reflog > ${out_dir}/GIT_COMMIT"
-	}
-	git_reflog = readFile("${out_dir}/GIT_COMMIT")
-	gitRefOldValue = (git_reflog =~ /moving from (.+) to (.+)/)[0][1]
-	gitRefNewValue = (git_reflog =~ /moving from (.+) to (.+)/)[0][2]
-}
-
 //===========================================================================================================
 //Routine responsible of sending the email notification once the build is completed
Index: benchmark/io/http/main.cfa
===================================================================
--- benchmark/io/http/main.cfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ benchmark/io/http/main.cfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -75,7 +75,22 @@
 	address.sin_port = htons( options.socket.port );
 
-	ret = bind( server_fd, (struct sockaddr *)&address, sizeof(address) );
-	if(ret < 0) {
-		abort( "bind error: (%d) %s\n", (int)errno, strerror(errno) );
+	int waited = 0;
+	for() {
+		ret = bind( server_fd, (struct sockaddr *)&address, sizeof(address) );
+		if(ret < 0) {
+			if(errno == 98) {
+				if(waited == 0) {
+					printf("Waiting for port\n");
+				} else {
+					printf("\r%d", waited);
+					fflush(stdout);
+				}
+				waited ++;
+				sleep( 1`s );
+				continue;
+			}
+			abort( "bind error: (%d) %s\n", (int)errno, strerror(errno) );
+		}
+		break;
 	}
 
Index: benchmark/readyQ/locality.go
===================================================================
--- benchmark/readyQ/locality.go	(revision 53449a48dee3324f96932ed8c4befe2756837314)
+++ benchmark/readyQ/locality.go	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -0,0 +1,124 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"math/rand"
+	"os"
+	"sync/atomic"
+	"time"
+	"golang.org/x/text/language"
+	"golang.org/x/text/message"
+)
+
+func handshake(stop chan struct {}, c chan [] uint64, data [] uint64, share bool) (bool, [] uint64) {
+	var s [] uint64 = data
+	if !share {
+		s = nil
+	}
+
+	// send the data
+	select {
+	case <- stop:
+		return true, nil
+	case c <- s:
+	}
+
+	// get the new data chunk
+	select {
+	case <- stop:
+		return true, nil
+	case n := <- c:
+		if share {
+			return false, n
+		}
+		return false, data
+	}
+}
+
+func local(result chan uint64, start chan struct{}, stop chan struct{}, size uint64, cnt uint64, channels []chan [] uint64, chan_cnt uint64, share bool) {
+	var data [] uint64
+	data = make([]uint64, size)
+	for i := uint64(0); i < size; i++ {
+		data[i] = 0
+	}
+	count := uint64(0)
+	<- start
+	for true {
+		for i := uint64(0); i < cnt; i++ {
+			data[rand.Uint64() % size] += 1
+		}
+
+		i := rand.Uint64() % chan_cnt
+		var closed bool
+		closed, data = handshake(stop, channels[i], data, share)
+		count += 1
+
+		if  closed { break }
+		if !clock_mode && count >= stop_count { break }
+	}
+
+	atomic.AddInt64(&threads_left, -1);
+	result <- count
+}
+
+func main() {
+
+	work_sizeOpt := flag.Uint64("w", 2    , "Number of words (uint64) per threads")
+	countOpt     := flag.Uint64("c", 2    , "Number of words (uint64) to touch")
+	shareOpt     := flag.Bool  ("s", false, "Pass the work data to the next thread when blocking")
+
+	bench_init()
+
+	size  := *work_sizeOpt
+	cnt   := *countOpt
+	share := *shareOpt
+
+	if ! (nthreads > nprocs) {
+		fmt.Fprintf(os.Stderr, "Must have more threads than procs\n")
+		os.Exit(1)
+	}
+
+	barrierStart := make(chan struct{})
+	barrierStop  := make(chan struct{})
+	threads_left = int64(nthreads)
+	result  := make(chan uint64)
+	channels := make([]chan [] uint64, nthreads - nprocs)
+	for i := range channels {
+		channels[i] = make(chan [] uint64, 1)
+	}
+
+	for i := 0; i < nthreads; i++ {
+		go local(result, barrierStart, barrierStop, size, cnt, channels, uint64(nthreads - nprocs), share)
+	}
+	fmt.Printf("Starting\n");
+
+	start := time.Now()
+	close(barrierStart)
+
+	wait(start, true);
+
+	close(barrierStop)
+	end := time.Now()
+	delta := end.Sub(start)
+
+	fmt.Printf("\nDone\n")
+
+	global_counter := uint64(0)
+	for i := 0; i < nthreads; i++ {
+		global_counter += <- result
+	}
+
+	p := message.NewPrinter(language.English)
+	p.Printf("Duration (ms)          : %f\n", delta.Seconds());
+	p.Printf("Number of processors   : %d\n", nprocs);
+	p.Printf("Number of threads      : %d\n", nthreads);
+	p.Printf("Work size (64bit words): %d\n", size);
+	p.Printf("Total Operations(ops)  : %15d\n", global_counter)
+	p.Printf("Ops per second         : %18.2f\n", float64(global_counter) / delta.Seconds())
+	p.Printf("ns per ops             : %18.2f\n", float64(delta.Nanoseconds()) / float64(global_counter))
+	p.Printf("Ops per threads        : %15d\n", global_counter / uint64(nthreads))
+	p.Printf("Ops per procs          : %15d\n", global_counter / uint64(nprocs))
+	p.Printf("Ops/sec/procs          : %18.2f\n", (float64(global_counter) / float64(nprocs)) / delta.Seconds())
+	p.Printf("ns per ops/procs       : %18.2f\n", float64(delta.Nanoseconds()) / (float64(global_counter) / float64(nprocs)))
+}
Index: doc/theses/thierry_delisle_PhD/code/readQ_example/Makefile
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/Makefile	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/Makefile	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -1,6 +1,18 @@
-all: gui-proto
+all: gui-proto-pthread gui-proto-fibre gui-proto-cforall
+
+PRECIOUS: thrdlib/libthrd-pthread.so thrdlib/libthrd-fibre.so thrdlib/libthrd-cforall.so
 
 CXXFLAGS = -fpic -g -O0 -I.
 
-gui-proto: proto-gui/main.o thrdlib/thread.o
-	$(CXX) -pthread -ldl -o ${@} ${^} -ftls-model=initial-exec
+thrdlib/libthrd-%.so:
+	+${MAKE} -C thrdlib libthrd-$*.so
+
+gui-proto-%: proto-gui/main.o thrdlib/libthrd-%.so Makefile
+	$(CXX) -Lthrdlib -Wl,--rpath,thrdlib -pthread -o $@ $< -lthrd-$*
+
+CFAINC=${HOME}/local/include/cfa-dev
+CFALIB=${HOME}/local/lib/cfa-dev/x64-debug
+CFAFLAGS=-z execstack -ftls-model=initial-exec -L${CFALIB} -Wl,-rpath,${CFALIB}
+
+gui-proto-cforall: proto-gui/main.o thrdlib/libthrd-cforall.so Makefile
+	$(CXX) -Lthrdlib -Wl,--rpath,thrdlib ${CFAFLAGS} -pthread -o $@ $< -lthrd-cforall -Wl,--push-state,--no-as-needed -lcfathread -lcfa -ldl -lm -Wl,--pop-state
Index: doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -11,27 +11,4 @@
 #include <getopt.h>
 using thrdlib::thread_t;
-
-
-extern __attribute__((aligned(128))) thread_local struct {
-	void * volatile this_thread;
-	void * volatile this_processor;
-	void * volatile this_stats;
-
-	struct {
-		volatile unsigned short disable_count;
-		volatile bool enabled;
-		volatile bool in_progress;
-	} preemption_state;
-
-	#if defined(__SIZEOF_INT128__)
-		__uint128_t rand_seed;
-	#else
-		uint64_t rand_seed;
-	#endif
-	struct {
-		uint64_t fwd_seed;
-		uint64_t bck_seed;
-	} ready_rng;
-} kernelTLS __attribute__ ((tls_model ( "initial-exec" )));
 
 //--------------------
@@ -148,4 +125,15 @@
 }
 
+typedef uint64_t __wyhash64_state_t;
+static inline uint64_t __wyhash64( __wyhash64_state_t & state ) {
+	state += 0x60bee2bee120fc15;
+	__uint128_t tmp;
+	tmp = (__uint128_t) state * 0xa3b195354a39b70d;
+	uint64_t m1 = (tmp >> 64) ^ tmp;
+	tmp = (__uint128_t)m1 * 0x1b03738712fad5c9;
+	uint64_t m2 = (tmp >> 64) ^ tmp;
+	return m2;
+}
+
 void Simulator( thread_t self ) {
 	for(unsigned i = 0; i < nproduce; i++) {
@@ -156,8 +144,10 @@
 		}
 
+		__wyhash64_state_t state = 0;
+
 		// Write the frame information
 		frame.number = i;
 		for( unsigned x = 0; x < fsize; x++ ) {
-			frame.data[x] = i;
+			frame.data[x] = __wyhash64(state);
 		}
 		std::cout << "Simulated " << i << std::endl;
@@ -187,5 +177,5 @@
 
 		std::cout << "Rendered " << i << std::endl;
-		assert(total == i * fsize);
+		// assert(total == i * fsize);
 
 		// Release
@@ -201,8 +191,6 @@
 int main(int argc, char * argv[]) {
 	nframes  = 3;
-	fsize    = 1000;
+	fsize    = 3840 * 2160 * 4 * 4;
 	nproduce = 60;
-
-	const char * framework;
 
 	for(;;) {
@@ -222,11 +210,4 @@
 			// Exit Case
 			case -1:
-				/* paranoid */ assert(optind <= argc);
-				if( optind == argc ) {
-					std::cerr << "Must specify a framework" << std::endl;
-					goto usage;
-
-				}
-				framework = argv[optind];
 				goto run;
 			case 'b':
@@ -261,5 +242,5 @@
 				std::cerr << opt << std::endl;
 			usage:
-				std::cerr << "Usage: " << argv[0] << " [options] framework" << std::endl;
+				std::cerr << "Usage: " << argv[0] << " [options]" << std::endl;
 				std::cerr << std::endl;
 				std::cerr << "  -b, --buff=COUNT    Number of frames to buffer" << std::endl;
@@ -270,6 +251,4 @@
 	}
 	run:
-	assert( framework );
-
 	frames.reset(new Frame[nframes]);
 	for(unsigned i = 0; i < nframes; i++) {
@@ -280,5 +259,5 @@
 	std::cout << "(Buffering " << nframes << ")" << std::endl;
 
-	thrdlib::init( framework, 2 );
+	thrdlib::init( 2 );
 
 	thread_t stats     = thrdlib::create( Stats );
Index: doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/Makefile
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/Makefile	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/Makefile	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -1,14 +1,14 @@
-all: fibre.so pthread.so cforall.so
+all: fibre.so libthrd-pthread.so.so cforall.so
 
 clean:
-	rm -rf fibre.so pthread.so
+	rm -rf fibre.so libthrd-pthread.so.so cforall.so
 
 CXXFLAGS=-Wall -Wextra -O3 -g -fpic -std=c++17 -pthread -ftls-model=initial-exec
 
-pthread.so: pthread.cpp Makefile
-	$(CXX) $(CXXFLAGS) -shared -o ${@} ${<}
+libthrd-pthread.so: thread.cpp thread.hpp Makefile
+	$(CXX) $(CXXFLAGS) -shared -o $@ $< -DWITH_PTHREADS
 
-fibre.so: fibre.cpp Makefile
-	$(CXX) $(CXXFLAGS) -shared -o ${@} ${<} -lfibre
+libthrd-fibre.so: thread.cpp thread.hpp Makefile
+	$(CXX) $(CXXFLAGS) -shared -o $@ $< -DWITH_LIBFIBRE -lfibre
 
 CFAINC=${HOME}/local/include/cfa-dev
@@ -16,4 +16,4 @@
 CFAFLAGS=-z execstack -I${CFAINC} -I${CFAINC}/concurrency -L${CFALIB} -Wl,-rpath,${CFALIB}
 
-cforall.so: cforall.cpp Makefile
-	$(CXX) $(CXXFLAGS) $(CFAFLAGS) -shared -o ${@} ${<} -lcfathread -lcfa -ldl -lm
+libthrd-cforall.so: thread.cpp thread.hpp Makefile
+	$(CXX) $(CXXFLAGS) $(CFAFLAGS) -shared -o $@ $< -DWITH_CFORALL -Wl,--push-state,--no-as-needed -lcfathread -lcfa -ldl -lm -Wl,--pop-state
Index: doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/pthread.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/pthread.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/pthread.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -1,2 +1,4 @@
+#pragma once
+
 #include <pthread.h>
 #include <errno.h>
@@ -97,3 +99,4 @@
 	// Basic kernel features
 	void thrdlib_init( int ) {}
+	void thrdlib_clean( void ) {}
 }
Index: doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -1,68 +1,28 @@
-#include "thread.hpp"
+#if !defined(WITH_PTHREADS) && !defined(WITH_LIBFIBRE) && !defined(WITH_CFORALL)
+#error must define WITH_PTHREADS, WITH_LIBFIBRE or WITH_CFORALL
+#endif
 
-#include <cstdarg>										// va_start, va_end
-#include <cstdio>
-#include <cstring>										// strlen
-extern "C" {
-	#include <unistd.h>										// _exit, getpid
-	#include <signal.h>
-	#include <dlfcn.h>										// dlopen, dlsym
-	#include <execinfo.h>									// backtrace, messages
-}
+#ifdef WITH_PTHREADS
+#include "pthread.hpp"
+#endif
+#ifdef WITH_LIBFIBRE
+#include "fibre.hpp"
+#endif
+#ifdef WITH_CFORALL
+#include "cforall.hpp"
+#endif
 
-#include <iostream>
-#include <string>
+namespace thrdlib {
+	//--------------------
+	// Basic thread support
+	void * create( void (*main)( void * ) ) { return (thread_t)thrdlib_create(  (void (*)( thread_t )) main ); }
+	void join  ( void * handle ) { thrdlib_join  ((thread_t)handle); }
+	void park  ( void * handle ) { thrdlib_park  ((thread_t)handle); }
+	void unpark( void * handle ) { thrdlib_unpark((thread_t)handle); }
+	void yield( void )  { thrdlib_yield(); }
 
-using thrdlib::thread_t;
-
-thread_t (*thrdlib::create)( void (*main)( thread_t ) ) = nullptr;
-void (*thrdlib::join)( thread_t handle ) = nullptr;
-void (*thrdlib::park)( thread_t handle ) = nullptr;
-void (*thrdlib::unpark)( thread_t handle ) = nullptr;
-void (*thrdlib::yield)( void ) = nullptr;
-void (*lib_clean)(void) = nullptr;
-
-typedef void (*fptr_t)();
-static fptr_t open_symbol( void * library, const char * symbol, bool required ) {
-	void * ptr = dlsym( library, symbol );
-
-	const char * error = dlerror();
-	if ( required && error ) {
-		std::cerr << "Fetching symbol '" << symbol << "' failed with error '" << error << "'\n";
-		std::abort();
-	}
-
-	return (fptr_t)ptr;
-}
-
-//--------------------
-// Basic kernel features
-void thrdlib::init( const char * name, int procs ) {
-	std::string file = __FILE__;
-	std::size_t found = file.find_last_of("/");
-  	std::string libname = file.substr(0,found+1) + name + ".so";
-
-	std::cout << "Use framework " << name << "(" << libname << ")\n";
-
-	void * library = dlopen( libname.c_str(), RTLD_NOW );
-	if ( const char * error = dlerror() ) {
-		std::cerr << "Could not open library '" << libname << "' from name '" << name <<"'\n";
-		std::cerr << "Error was : '" << error << "'\n";
-		std::abort();
-	}
-
-	void (*lib_init)( int ) = (void (*)( int ))open_symbol( library, "thrdlib_init", false );
-	lib_clean = open_symbol( library, "thrdlib_clean" , false );
-
-	thrdlib::create = (typeof(thrdlib::create))open_symbol( library, "thrdlib_create", true  );
-	thrdlib::join   = (typeof(thrdlib::join  ))open_symbol( library, "thrdlib_join"  , true  );
-	thrdlib::park   = (typeof(thrdlib::park  ))open_symbol( library, "thrdlib_park"  , true  );
-	thrdlib::unpark = (typeof(thrdlib::unpark))open_symbol( library, "thrdlib_unpark", true  );
-	thrdlib::yield  = (typeof(thrdlib::yield ))open_symbol( library, "thrdlib_yield" , true  );
-
-	lib_init( procs );
-}
-
-void thrdlib::clean( void ) {
-	if(lib_clean) lib_clean();
-}
+	//--------------------
+	// Basic kernel features
+	void init( int procs ) { thrdlib_init(procs); }
+	void clean( void ) { thrdlib_clean(); }
+};
Index: doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -6,13 +6,13 @@
 	//--------------------
 	// Basic thread support
-	extern thread_t (*create)( void (*main)( thread_t ) );
-	extern void (*join)( thread_t handle );
-	extern void (*park)( thread_t handle );
-	extern void (*unpark)( thread_t handle );
-	extern void (*yield)( void ) ;
+	extern thread_t create( void (*main)( thread_t ) );
+	extern void join( thread_t handle );
+	extern void park( thread_t handle );
+	extern void unpark( thread_t handle );
+	extern void yield( void ) ;
 
 	//--------------------
 	// Basic kernel features
-	extern void init( const char * name, int procs );
+	extern void init( int procs );
 	extern void clean( void );
 };
Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ libcfa/src/concurrency/coroutine.cfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -10,6 +10,6 @@
 // Created On       : Mon Nov 28 12:27:26 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Oct 23 23:05:24 2020
-// Update Count     : 22
+// Last Modified On : Tue Dec 15 12:06:04 2020
+// Update Count     : 23
 //
 
@@ -28,4 +28,7 @@
 #include "kernel_private.hfa"
 #include "exception.hfa"
+#include "math.hfa"
+
+#define CFA_COROUTINE_USE_MMAP 0
 
 #define __CFA_INVOKE_PRIVATE__
@@ -85,6 +88,8 @@
 static const size_t MinStackSize = 1000;
 extern size_t __page_size;				// architecture pagesize HACK, should go in proper runtime singleton
+extern int __map_prot;
 
 void __stack_prepare( __stack_info_t * this, size_t create_size );
+void __stack_clean  ( __stack_info_t * this );
 
 //-----------------------------------------------------------------------------
@@ -107,16 +112,5 @@
 	bool userStack = ((intptr_t)this.storage & 0x1) != 0;
 	if ( ! userStack && this.storage ) {
-		__attribute__((may_alias)) intptr_t * istorage = (intptr_t *)&this.storage;
-		*istorage &= (intptr_t)-1;
-
-		void * storage = this.storage->limit;
-		__cfaabi_dbg_debug_do(
-			storage = (char*)(storage) - __page_size;
-			if ( mprotect( storage, __page_size, PROT_READ | PROT_WRITE ) == -1 ) {
-				abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) );
-			}
-		);
-		__cfaabi_dbg_print_safe("Kernel : Deleting stack %p\n", storage);
-		free( storage );
+		__stack_clean( &this );
 	}
 }
@@ -167,24 +161,58 @@
 	assert(__page_size != 0l);
 	size_t size = libCeiling( storageSize, 16 ) + stack_data_size;
+	size = ceiling(size, __page_size);
 
 	// If we are running debug, we also need to allocate a guardpage to catch stack overflows.
 	void * storage;
-	__cfaabi_dbg_debug_do(
-		storage = memalign( __page_size, size + __page_size );
-	);
-	__cfaabi_dbg_no_debug_do(
-		storage = (void*)malloc(size);
-	);
-
+	#if CFA_COROUTINE_USE_MMAP
+		storage = mmap(0p, size + __page_size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+		if(storage == ((void*)-1)) {
+			abort( "coroutine stack creation : internal error, mmap failure, error(%d) %s.", errno, strerror( errno ) );
+		}
+		if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) {
+			abort( "coroutine stack creation : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) );
+		} // if
+		storage = (void *)(((intptr_t)storage) + __page_size);
+	#else
+		__cfaabi_dbg_debug_do(
+			storage = memalign( __page_size, size + __page_size );
+		);
+		__cfaabi_dbg_no_debug_do(
+			storage = (void*)malloc(size);
+		);
+
+		__cfaabi_dbg_debug_do(
+			if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) {
+				abort( "__stack_alloc : internal error, mprotect failure, error(%d) %s.", (int)errno, strerror( (int)errno ) );
+			}
+			storage = (void *)(((intptr_t)storage) + __page_size);
+		);
+	#endif
 	__cfaabi_dbg_print_safe("Kernel : Created stack %p of size %zu\n", storage, size);
-	__cfaabi_dbg_debug_do(
-		if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) {
-			abort( "__stack_alloc : internal error, mprotect failure, error(%d) %s.", (int)errno, strerror( (int)errno ) );
-		}
-		storage = (void *)(((intptr_t)storage) + __page_size);
-	);
 
 	verify( ((intptr_t)storage & (libAlign() - 1)) == 0ul );
 	return [storage, size];
+}
+
+void __stack_clean  ( __stack_info_t * this ) {
+	size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t);
+	void * storage = this->storage->limit;
+
+	#if CFA_COROUTINE_USE_MMAP
+		storage = (void *)(((intptr_t)storage) - __page_size);
+		if(munmap(storage, size + __page_size) == -1) {
+			abort( "coroutine stack destruction : internal error, munmap failure, error(%d) %s.", errno, strerror( errno ) );
+		}
+	#else
+		__cfaabi_dbg_debug_do(
+			storage = (char*)(storage) - __page_size;
+			if ( mprotect( storage, __page_size, __map_prot ) == -1 ) {
+				abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) );
+			}
+		);
+
+		free( storage );
+	#endif
+	__cfaabi_dbg_print_safe("Kernel : Deleting stack %p\n", storage);
 }
 
@@ -210,7 +238,7 @@
 	assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %zd bytes for a stack.", size, MinStackSize );
 
-	this->storage = (__stack_t *)((intptr_t)storage + size);
+	this->storage = (__stack_t *)((intptr_t)storage + size - sizeof(__stack_t));
 	this->storage->limit = storage;
-	this->storage->base  = (void*)((intptr_t)storage + size);
+	this->storage->base  = (void*)((intptr_t)storage + size - sizeof(__stack_t));
 	this->storage->exception_context.top_resume = 0p;
 	this->storage->exception_context.current_exception = 0p;
Index: libcfa/src/concurrency/coroutine.hfa
===================================================================
--- libcfa/src/concurrency/coroutine.hfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ libcfa/src/concurrency/coroutine.hfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -102,5 +102,7 @@
 }
 
-extern void __stack_prepare   ( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
+extern void __stack_prepare( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
+extern void __stack_clean  ( __stack_info_t * this );
+
 
 // Suspend implementation inlined for performance
@@ -142,8 +144,6 @@
 
 	if( unlikely(dst->context.SP == 0p) ) {
-		active_thread()->curr_cor = dst;
 		__stack_prepare(&dst->stack, 65000);
 		__cfactx_start(main, dst, cor, __cfactx_invoke_coroutine);
-		active_thread()->curr_cor = src;
 	}
 
Index: libcfa/src/concurrency/io/setup.cfa
===================================================================
--- libcfa/src/concurrency/io/setup.cfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ libcfa/src/concurrency/io/setup.cfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -17,4 +17,9 @@
 #define _GNU_SOURCE         /* See feature_test_macros(7) */
 
+#if defined(__CFA_DEBUG__)
+	// #define __CFA_DEBUG_PRINT_IO__
+	// #define __CFA_DEBUG_PRINT_IO_CORE__
+#endif
+
 #include "io/types.hfa"
 #include "kernel.hfa"
@@ -111,5 +116,5 @@
 
 	void __kernel_io_startup(void) {
-		__cfaabi_dbg_print_safe( "Kernel : Creating EPOLL instance\n" );
+		__cfadbg_print_safe(io_core, "Kernel : Creating EPOLL instance\n" );
 
 		iopoll.epollfd = epoll_create1(0);
@@ -118,5 +123,5 @@
 		}
 
-		__cfaabi_dbg_print_safe( "Kernel : Starting io poller thread\n" );
+		__cfadbg_print_safe(io_core, "Kernel : Starting io poller thread\n" );
 
 		iopoll.run = true;
@@ -132,6 +137,5 @@
 		// Wait for the io poller thread to finish
 
-		pthread_join( iopoll.thrd, 0p );
-		free( iopoll.stack );
+		__destroy_pthread( iopoll.thrd, iopoll.stack, 0p );
 
 		int ret = close(iopoll.epollfd);
@@ -142,5 +146,5 @@
 		// Io polling is now fully stopped
 
-		__cfaabi_dbg_print_safe( "Kernel : IO poller stopped\n" );
+		__cfadbg_print_safe(io_core, "Kernel : IO poller stopped\n" );
 	}
 
@@ -150,5 +154,5 @@
 		id.id = doregister(&id);
 		__cfaabi_tls.this_proc_id = &id;
-		__cfaabi_dbg_print_safe( "Kernel : IO poller thread starting\n" );
+		__cfadbg_print_safe(io_core, "Kernel : IO poller thread starting\n" );
 
 		// Block signals to control when they arrive
@@ -185,5 +189,5 @@
 		}
 
-		__cfaabi_dbg_print_safe( "Kernel : IO poller thread stopping\n" );
+		__cfadbg_print_safe(io_core, "Kernel : IO poller thread stopping\n" );
 		unregister(&id);
 		return 0p;
Index: libcfa/src/concurrency/kernel/startup.cfa
===================================================================
--- libcfa/src/concurrency/kernel/startup.cfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ libcfa/src/concurrency/kernel/startup.cfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -29,4 +29,7 @@
 #include "kernel_private.hfa"
 #include "startup.hfa"          // STARTUP_PRIORITY_XXX
+#include "math.hfa"
+
+#define CFA_PROCESSOR_USE_MMAP 0
 
 //-----------------------------------------------------------------------------
@@ -114,5 +117,5 @@
 }
 
-size_t __page_size = 0;
+extern size_t __page_size;
 
 //-----------------------------------------------------------------------------
@@ -158,6 +161,4 @@
 	/* paranoid */ verify( ! __preemption_enabled() );
 	__cfadbg_print_safe(runtime_core, "Kernel : Starting\n");
-
-	__page_size = sysconf( _SC_PAGESIZE );
 
 	__cfa_dbg_global_clusters.list{ __get };
@@ -539,4 +540,5 @@
 }
 
+extern size_t __page_size;
 void ^?{}(processor & this) with( this ){
 	if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) {
@@ -550,8 +552,5 @@
 	}
 
-	int err = pthread_join( kernel_thread, 0p );
-	if( err != 0 ) abort("KERNEL ERROR: joining processor %p caused error %s\n", &this, strerror(err));
-
-	free( this.stack );
+	__destroy_pthread( kernel_thread, this.stack, 0p );
 
 	disable_interrupts();
@@ -678,14 +677,26 @@
 
 	void * stack;
-	__cfaabi_dbg_debug_do(
-		stack = memalign( __page_size, stacksize + __page_size );
-		// pthread has no mechanism to create the guard page in user supplied stack.
+	#if CFA_PROCESSOR_USE_MMAP
+		stacksize = ceiling( stacksize, __page_size ) + __page_size;
+		stack = mmap(0p, stacksize, __map_prot, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+		if(stack == ((void*)-1)) {
+			abort( "pthread stack creation : internal error, mmap failure, error(%d) %s.", errno, strerror( errno ) );
+		}
 		if ( mprotect( stack, __page_size, PROT_NONE ) == -1 ) {
-			abort( "mprotect : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) );
+			abort( "pthread stack creation : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) );
 		} // if
-	);
-	__cfaabi_dbg_no_debug_do(
-		stack = malloc( stacksize );
-	);
+	#else
+		__cfaabi_dbg_debug_do(
+			stack = memalign( __page_size, stacksize + __page_size );
+			// pthread has no mechanism to create the guard page in user supplied stack.
+			if ( mprotect( stack, __page_size, PROT_NONE ) == -1 ) {
+				abort( "mprotect : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) );
+			} // if
+		);
+		__cfaabi_dbg_no_debug_do(
+			stack = malloc( stacksize );
+		);
+	#endif
+
 
 	check( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );
@@ -694,4 +705,28 @@
 	return stack;
 }
+
+void __destroy_pthread( pthread_t pthread, void * stack, void ** retval ) {
+	int err = pthread_join( pthread, retval );
+	if( err != 0 ) abort("KERNEL ERROR: joining pthread %p caused error %s\n", (void*)pthread, strerror(err));
+
+	#if CFA_PROCESSOR_USE_MMAP
+		pthread_attr_t attr;
+
+		check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
+
+		size_t stacksize;
+		// default stack size, normally defined by shell limit
+		check( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );
+		assert( stacksize >= PTHREAD_STACK_MIN );
+		stacksize += __page_size;
+
+		if(munmap(stack, stacksize) == -1) {
+			abort( "pthread stack destruction : internal error, munmap failure, error(%d) %s.", errno, strerror( errno ) );
+		}
+	#else
+		free( stack );
+	#endif
+}
+
 
 #if defined(__CFA_WITH_VERIFY__)
Index: libcfa/src/concurrency/kernel_private.hfa
===================================================================
--- libcfa/src/concurrency/kernel_private.hfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ libcfa/src/concurrency/kernel_private.hfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -49,4 +49,5 @@
 
 void * __create_pthread( pthread_t *, void * (*)(void *), void * );
+void __destroy_pthread( pthread_t pthread, void * stack, void ** retval );
 
 
Index: libcfa/src/concurrency/preemption.cfa
===================================================================
--- libcfa/src/concurrency/preemption.cfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ libcfa/src/concurrency/preemption.cfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -575,6 +575,5 @@
 	// Wait for the preemption thread to finish
 
-	pthread_join( alarm_thread, 0p );
-	free( alarm_stack );
+	__destroy_pthread( alarm_thread, alarm_stack, 0p );
 
 	// Preemption is now fully stopped
Index: libcfa/src/heap.cfa
===================================================================
--- libcfa/src/heap.cfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ libcfa/src/heap.cfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -10,9 +10,10 @@
 // Created On       : Tue Dec 19 21:58:35 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Sep  7 22:17:46 2020
-// Update Count     : 957
+// Last Modified On : Wed Dec 16 12:28:25 2020
+// Update Count     : 1023
 //
 
 #include <unistd.h>										// sbrk, sysconf
+#include <stdlib.h>										// EXIT_FAILURE
 #include <stdbool.h>									// true, false
 #include <stdio.h>										// snprintf, fileno
@@ -71,5 +72,5 @@
 	// Define the default extension heap amount in units of bytes. When the uC++ supplied heap reaches the brk address,
 	// the brk address is extended by the extension amount.
-	__CFA_DEFAULT_HEAP_EXPANSION__ = (1 * 1024 * 1024),
+	__CFA_DEFAULT_HEAP_EXPANSION__ = (10 * 1024 * 1024),
 
 	// Define the mmap crossover point during allocation. Allocations less than this amount are allocated from buckets;
@@ -115,5 +116,6 @@
 
 // statically allocated variables => zero filled.
-static size_t pageSize;									// architecture pagesize
+size_t __page_size;										// architecture pagesize
+int __map_prot;											// common mmap/mprotect protection
 static size_t heapExpand;								// sbrk advance
 static size_t mmapStart;								// cross over point for mmap
@@ -249,5 +251,5 @@
 #endif // FASTLOOKUP
 
-static int mmapFd = -1;									// fake or actual fd for anonymous file
+static const off_t mmapFd = -1;							// fake or actual fd for anonymous file
 #ifdef __CFA_DEBUG__
 static bool heapBoot = 0;								// detect recursion during boot
@@ -374,5 +376,5 @@
 
 static inline bool setMmapStart( size_t value ) {		// true => mmapped, false => sbrk
-  if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return false;
+  if ( value < __page_size || bucketSizes[NoBucketSizes - 1] < value ) return false;
 	mmapStart = value;									// set global
 
@@ -436,5 +438,5 @@
 	header = headerAddr( addr );
 
-  if ( unlikely( heapEnd < addr ) ) {					// mmapped ?
+  if ( unlikely( addr < heapBegin || heapEnd < addr ) ) { // mmapped ?
 		fakeHeader( header, alignment );
 		size = header->kind.real.blockSize & -3;		// mmap size
@@ -443,5 +445,5 @@
 
 	#ifdef __CFA_DEBUG__
-	checkHeader( addr < heapBegin, name, addr );		// bad low address ?
+	checkHeader( header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
 	#endif // __CFA_DEBUG__
 
@@ -464,4 +466,23 @@
 } // headers
 
+#ifdef __CFA_DEBUG__
+#if __SIZEOF_POINTER__ == 4
+#define MASK 0xdeadbeef
+#else
+#define MASK 0xdeadbeefdeadbeef
+#endif
+#define STRIDE size_t
+
+static void * Memset( void * addr, STRIDE size ) {		// debug only
+	if ( size % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, size %zd not multiple of %zd.", size, sizeof(STRIDE) );
+	if ( (STRIDE)addr % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, addr %p not multiple of %zd.", addr, sizeof(STRIDE) );
+
+	STRIDE * end = (STRIDE *)addr + size / sizeof(STRIDE);
+	for ( STRIDE * p = (STRIDE *)addr; p < end; p += 1 ) *p = MASK;
+	return addr;
+} // Memset
+#endif // __CFA_DEBUG__
+
+
 #define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes."
 
@@ -472,8 +493,15 @@
 		// If the size requested is bigger than the current remaining storage, increase the size of the heap.
 
-		size_t increase = ceiling2( size > heapExpand ? size : heapExpand, libAlign() );
+		size_t increase = ceiling2( size > heapExpand ? size : heapExpand, __page_size );
+		// Do not call abort or strerror( errno ) as they may call malloc.
 		if ( sbrk( increase ) == (void *)-1 ) {			// failed, no memory ?
 			unlock( extlock );
-			abort( NO_MEMORY_MSG, size );				// give up
+			__cfaabi_bits_print_nolock( STDERR_FILENO, NO_MEMORY_MSG, size );
+			_exit( EXIT_FAILURE );
+		} // if
+		if ( mprotect( (char *)heapEnd + heapRemaining, increase, __map_prot ) ) {
+			unlock( extlock );
+			__cfaabi_bits_print_nolock( STDERR_FILENO, "extend() : internal error, mprotect failure, heapEnd:%p size:%zd, errno:%d.\n", heapEnd, increase, errno );
+			_exit( EXIT_FAILURE );
 		} // if
 		#ifdef __STATISTICS__
@@ -483,5 +511,6 @@
 		#ifdef __CFA_DEBUG__
 		// Set new memory to garbage so subsequent uninitialized usages might fail.
-		memset( (char *)heapEnd + heapRemaining, '\377', increase );
+		memset( (char *)heapEnd + heapRemaining, '\xde', increase );
+		//Memset( (char *)heapEnd + heapRemaining, increase );
 		#endif // __CFA_DEBUG__
 		rem = heapRemaining + increase - size;
@@ -542,6 +571,6 @@
 		block->header.kind.real.home = freeElem;		// pointer back to free list of apropriate size
 	} else {											// large size => mmap
-  if ( unlikely( size > ULONG_MAX - pageSize ) ) return 0p;
-		tsize = ceiling2( tsize, pageSize );			// must be multiple of page size
+  if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p;
+		tsize = ceiling2( tsize, __page_size );			// must be multiple of page size
 		#ifdef __STATISTICS__
 		__atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST );
@@ -549,13 +578,14 @@
 		#endif // __STATISTICS__
 
-		block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
+		block = (HeapManager.Storage *)mmap( 0, tsize, __map_prot, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
 		if ( block == (HeapManager.Storage *)MAP_FAILED ) { // failed ?
 			if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory
 			// Do not call strerror( errno ) as it may call malloc.
-			abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu error:%d.", &heapManager, tsize, errno );
+			abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu errno:%d.", &heapManager, tsize, errno );
 		} //if
 		#ifdef __CFA_DEBUG__
 		// Set new memory to garbage so subsequent uninitialized usages might fail.
-		memset( block, '\377', tsize );
+		memset( block, '\xde', tsize );
+		//Memset( block, tsize );
 		#endif // __CFA_DEBUG__
 		block->header.kind.real.blockSize = tsize;		// storage size for munmap
@@ -597,14 +627,13 @@
 		#endif // __STATISTICS__
 		if ( munmap( header, size ) == -1 ) {
-			#ifdef __CFA_DEBUG__
 			abort( "Attempt to deallocate storage %p not allocated or with corrupt header.\n"
 				   "Possible cause is invalid pointer.",
 				   addr );
-			#endif // __CFA_DEBUG__
 		} // if
 	} else {
 		#ifdef __CFA_DEBUG__
 		// Set free memory to garbage so subsequent usages might fail.
-		memset( ((HeapManager.Storage *)header)->data, '\377', freeElem->blockSize - sizeof( HeapManager.Storage ) );
+		memset( ((HeapManager.Storage *)header)->data, '\xde', freeElem->blockSize - sizeof( HeapManager.Storage ) );
+		//Memset( ((HeapManager.Storage *)header)->data, freeElem->blockSize - sizeof( HeapManager.Storage ) );
 		#endif // __CFA_DEBUG__
 
@@ -648,8 +677,8 @@
 		for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
 		#else
-		// for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
+			for(;;) {
+//		for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
 //		for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
-		for ( HeapManager.Storage * p ;; /* p = getNext( p )->top */) {
-			HeapManager.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works`
+//			HeapManager.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works`
 //			typeof(p) temp = (( p )`next)->top;			// FIX ME: direct assignent fails, initialization works`
 //			p = temp;
@@ -675,5 +704,6 @@
 
 static void ?{}( HeapManager & manager ) with( manager ) {
-	pageSize = sysconf( _SC_PAGESIZE );
+	__page_size = sysconf( _SC_PAGESIZE );
+	__map_prot = PROT_READ | PROT_WRITE | PROT_EXEC;
 
 	for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
@@ -695,5 +725,5 @@
 
 	char * end = (char *)sbrk( 0 );
-	heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
+	heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, __page_size ) - end ); // move start of heap to multiple of alignment
 } // HeapManager
 
@@ -713,5 +743,4 @@
 	#ifdef __CFA_DEBUG__
 	if ( heapBoot ) {									// check for recursion during system boot
-		// DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
 		abort( "boot() : internal error, recursively invoked during system boot." );
 	} // if
@@ -935,5 +964,5 @@
 	  		header->kind.real.size = size;				// reset allocation size
 	  		if ( unlikely( ozfill ) && size > osize ) {	// previous request zero fill and larger ?
-	  			memset( (char *)oaddr + osize, (int)'\0', size - osize ); // initialize added storage
+	  			memset( (char *)oaddr + osize, '\0', size - osize ); // initialize added storage
 	  		} // if
 			return oaddr;
@@ -960,5 +989,5 @@
 			header->kind.real.blockSize |= 2;			// mark new request as zero filled
 			if ( size > osize ) {						// previous request larger ?
-				memset( (char *)naddr + osize, (int)'\0', size - osize ); // initialize added storage
+				memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage
 			} // if
 		} // if
@@ -999,4 +1028,5 @@
 		return cmemalignNoStats( alignment, dim, elemSize );
 	} // cmemalign
+
 
 	// Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
@@ -1017,8 +1047,9 @@
 	} // posix_memalign
 
+
 	// Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the
 	// page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
 	void * valloc( size_t size ) {
-		return memalign( pageSize, size );
+		return memalign( __page_size, size );
 	} // valloc
 
@@ -1026,5 +1057,5 @@
 	// Same as valloc but rounds size to multiple of page size.
 	void * pvalloc( size_t size ) {
-		return memalign( pageSize, ceiling2( size, pageSize ) );
+		return memalign( __page_size, ceiling2( size, __page_size ) );
 	} // pvalloc
 
@@ -1165,5 +1196,5 @@
 		choose( option ) {
 		  case M_TOP_PAD:
-			heapExpand = ceiling2( value, pageSize ); return 1;
+			heapExpand = ceiling2( value, __page_size ); return 1;
 		  case M_MMAP_THRESHOLD:
 			if ( setMmapStart( value ) ) return 1;
@@ -1327,5 +1358,5 @@
 		header->kind.real.blockSize |= 2;				// mark new request as zero filled
 		if ( size > osize ) {							// previous request larger ?
-			memset( (char *)naddr + osize, (int)'\0', size - osize ); // initialize added storage
+			memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage
 		} // if
 	} // if
Index: libcfa/src/stdlib.hfa
===================================================================
--- libcfa/src/stdlib.hfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ libcfa/src/stdlib.hfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jan 28 17:12:35 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Dec  8 18:27:22 2020
-// Update Count     : 524
+// Last Modified On : Sat Dec 12 13:52:34 2020
+// Update Count     : 536
 //
 
@@ -49,5 +49,5 @@
 
 static inline forall( dtype T | sized(T) ) {
-	// Cforall safe equivalents, i.e., implicit size specification
+	// CFA safe equivalents, i.e., implicit size specification
 
 	T * malloc( void ) {
@@ -234,5 +234,5 @@
 
 static inline forall( dtype T | sized(T) ) {
-	// Cforall safe initialization/copy, i.e., implicit size specification, non-array types
+	// CFA safe initialization/copy, i.e., implicit size specification, non-array types
 	T * memset( T * dest, char fill ) {
 		return (T *)memset( dest, fill, sizeof(T) );
@@ -243,5 +243,5 @@
 	} // memcpy
 
-	// Cforall safe initialization/copy, i.e., implicit size specification, array types
+	// CFA safe initialization/copy, i.e., implicit size specification, array types
 	T * amemset( T dest[], char fill, size_t dim ) {
 		return (T *)(void *)memset( dest, fill, dim * sizeof(T) ); // C memset
@@ -253,12 +253,16 @@
 } // distribution
 
-// Cforall deallocation for multiple objects
+// CFA deallocation for multiple objects
+static inline forall( dtype T )							// FIX ME, problems with 0p in list
+void free( T * ptr ) {
+	free( (void *)ptr );								// C free
+} // free
 static inline forall( dtype T, ttype TT | { void free( TT ); } )
-void free( T * addr, TT rest ) {
-	free( ( void *)addr );								// use C free
+void free( T * ptr, TT rest ) {
+	free( ptr );
 	free( rest );
 } // free
 
-// Cforall allocation/deallocation and constructor/destructor, non-array types
+// CFA allocation/deallocation and constructor/destructor, non-array types
 static inline forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } )
 T * new( TT p ) {
@@ -272,7 +276,6 @@
 		^(*ptr){};										// run destructor
 	} // if
-	free( ptr );
+	free( ptr );										// always call free
 } // delete
-
 static inline forall( dtype T, ttype TT | { void ^?{}( T & ); void delete( TT ); } )
 void delete( T * ptr, TT rest ) {
@@ -281,5 +284,5 @@
 } // delete
 
-// Cforall allocation/deallocation and constructor/destructor, array types
+// CFA allocation/deallocation and constructor/destructor, array types
 forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } ) T * anew( size_t dim, TT p );
 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] );
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Convert.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -55,8 +55,8 @@
 
 // these need to be accessed in new FixInit now
-ast::Type * sizeType = nullptr;
-ast::FunctionDecl * dereferenceOperator = nullptr;
-ast::StructDecl   * dtorStruct = nullptr;
-ast::FunctionDecl * dtorStructDestroy = nullptr;
+ast::ptr<ast::Type> sizeType = nullptr;
+const ast::FunctionDecl * dereferenceOperator = nullptr;
+const ast::StructDecl   * dtorStruct = nullptr;
+const ast::FunctionDecl * dtorStructDestroy = nullptr;
 
 }
@@ -205,5 +205,10 @@
 		ftype->parameters = get<DeclarationWithType>().acceptL(node->params);
 
-		ftype->forall = get<TypeDecl>().acceptL( node->type->forall );
+		ftype->forall = get<TypeDecl>().acceptL( node->type_params );
+		if (!node->assertions.empty()) {
+			assert(!ftype->forall.empty());
+			// find somewhere to place assertions back, for convenience it is the last slot
+			ftype->forall.back()->assertions = get<DeclarationWithType>().acceptL(node->assertions);
+		}
 
 		visitType(node->type, ftype);
@@ -233,5 +238,4 @@
 	const ast::Decl * namedTypePostamble( NamedTypeDecl * decl, const ast::NamedTypeDecl * node ) {
 		// base comes from constructor
-		decl->parameters = get<TypeDecl>().acceptL( node->params );
 		decl->assertions = get<DeclarationWithType>().acceptL( node->assertions );
 		declPostamble( decl, node );
@@ -603,11 +607,6 @@
 
 		for (decltype(src->begin()) src_i = src->begin(); src_i != src->end(); src_i++) {
-			rslt->add( src_i->first,
+			rslt->add( src_i->first.typeString(),
 			           get<Type>().accept1(src_i->second) );
-		}
-
-		for (decltype(src->beginVar()) src_i = src->beginVar(); src_i != src->endVar(); src_i++) {
-			rslt->addVar( src_i->first,
-			              get<Expression>().accept1(src_i->second) );
 		}
 
@@ -1213,10 +1212,29 @@
 		// ty->returnVals = get<DeclarationWithType>().acceptL( node->returns );
 		// ty->parameters = get<DeclarationWithType>().acceptL( node->params );
-		ty->forall = get<TypeDecl>().acceptL( node->forall );
+
+		auto types = get<TypeInstType>().acceptL( node->forall );
+		for (auto t : types) {
+			auto newT = new TypeDecl(*t->baseType);
+			newT->name = t->name; // converted by typeString()
+			for (auto asst : newT->assertions) delete asst;
+			newT->assertions.clear();
+			ty->forall.push_back(newT);
+		}
+		auto assts = get<VariableExpr>().acceptL( node->assertions );
+		if (!assts.empty()) {
+			assert(!types.empty());
+			for (auto asst : assts) {
+				auto newDecl = new ObjectDecl(*strict_dynamic_cast<ObjectDecl*>(asst->var));
+				delete newDecl->type;
+				newDecl->type = asst->result->clone();
+				newDecl->storageClasses.is_extern = true; // hack
+				ty->forall.back()->assertions.push_back(newDecl);
+			}
+		}
+
 		return visitType( node, ty );
 	}
 
 	const ast::Type * postvisit( const ast::BaseInstType * old, ReferenceToType * ty ) {
-		ty->forall = get<TypeDecl>().acceptL( old->forall );
 		ty->parameters = get<Expression>().acceptL( old->params );
 		ty->hoistType = old->hoistType;
@@ -1301,5 +1319,5 @@
 			ty = new TypeInstType{
 				cv( node ),
-				node->name,
+				node->typeString(),
 				get<TypeDecl>().accept1( node->base ),
 				get<Attribute>().acceptL( node->attributes )
@@ -1308,5 +1326,5 @@
 			ty = new TypeInstType{
 				cv( node ),
-				node->name,
+				node->typeString(),
 				node->kind == ast::TypeDecl::Ftype,
 				get<Attribute>().acceptL( node->attributes )
@@ -1433,5 +1451,5 @@
 	/// at conversion stage, all created nodes are guaranteed to be unique, therefore
 	/// const_casting out of smart pointers is permitted.
-	std::unordered_map< const BaseSyntaxNode *, ast::ptr<ast::Node> > cache = {};
+	std::unordered_map< const BaseSyntaxNode *, ast::readonly<ast::Node> > cache = {};
 
 	// Local Utilities:
@@ -1567,4 +1585,16 @@
 		// can function type have attributes? seems not to be the case.
 		// visitType(old->type, ftype);
+
+		// collect assertions and put directly in FunctionDecl
+		std::vector<ast::ptr<ast::DeclWithType>> assertions;
+		for (auto & param: forall) {
+			for (auto & asst: param->assertions) {
+				assertf(asst->unique(), "newly converted decl must be unique");
+				assertions.emplace_back(asst);
+			}
+			auto mut = param.get_and_mutate();
+			assertf(mut == param, "newly converted decl must be unique");
+			mut->assertions.clear();
+		}
 
 		auto decl = new ast::FunctionDecl{
@@ -1586,4 +1616,5 @@
 		cache.emplace( old, decl );
 
+		decl->assertions = std::move(assertions);
 		decl->withExprs = GET_ACCEPT_V(withExprs, Expr);
 		decl->stmts = GET_ACCEPT_1(statements, CompoundStmt);
@@ -1704,5 +1735,4 @@
 		cache.emplace( old, decl );
 		decl->assertions = GET_ACCEPT_V(assertions, DeclWithType);
-		decl->params     = GET_ACCEPT_V(parameters, TypeDecl);
 		decl->extension  = old->extension;
 		decl->uniqueId   = old->uniqueId;
@@ -1720,5 +1750,4 @@
 		);
 		decl->assertions = GET_ACCEPT_V(assertions, DeclWithType);
-		decl->params     = GET_ACCEPT_V(parameters, TypeDecl);
 		decl->extension  = old->extension;
 		decl->uniqueId   = old->uniqueId;
@@ -2070,8 +2099,12 @@
 	}
 
+	// TypeSubstitution shouldn't exist yet in old.
 	ast::TypeSubstitution * convertTypeSubstitution(const TypeSubstitution * old) {
-
+		
 		if (!old) return nullptr;
-
+		if (old->empty()) return nullptr;
+		assert(false);
+
+		/*
 		ast::TypeSubstitution *rslt = new ast::TypeSubstitution();
 
@@ -2081,10 +2114,6 @@
 		}
 
-		for (decltype(old->beginVar()) old_i = old->beginVar(); old_i != old->endVar(); old_i++) {
-			rslt->addVar( old_i->first,
-			              getAccept1<ast::Expr>(old_i->second) );
-		}
-
 		return rslt;
+		*/
 	}
 
@@ -2614,10 +2643,18 @@
 			ty->params.emplace_back(v->get_type());
 		}
-		ty->forall = GET_ACCEPT_V( forall, TypeDecl );
+		// xxx - when will this be non-null?
+		// will have to create dangling (no-owner) decls to be pointed to
+		auto foralls = GET_ACCEPT_V( forall, TypeDecl );
+
+		for (auto & param : foralls) {
+			ty->forall.emplace_back(new ast::TypeInstType(param->name, param));
+			for (auto asst : param->assertions) {
+				ty->assertions.emplace_back(new ast::VariableExpr({}, asst));
+			}
+		}
 		visitType( old, ty );
 	}
 
 	void postvisit( const ReferenceToType * old, ast::BaseInstType * ty ) {
-		ty->forall = GET_ACCEPT_V( forall, TypeDecl );
 		ty->params = GET_ACCEPT_V( parameters, Expr );
 		ty->hoistType = old->hoistType;
@@ -2807,4 +2844,10 @@
 	ConverterOldToNew c;
 	ast::TranslationUnit unit;
+	if (Validate::SizeType) {
+		// this should be a BasicType.
+		auto old = strict_dynamic_cast<BasicType *>(Validate::SizeType);
+		ast::sizeType = new ast::BasicType{ (ast::BasicType::Kind)(unsigned)old->kind };
+	}
+
 	for(auto d : translationUnit) {
 		d->accept( c );
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Decl.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -50,20 +50,22 @@
 
 FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name, 
-		std::vector<ptr<TypeDecl>>&& forall,
-		std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
-		CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
-		std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
-	: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
-	  stmts( stmts ) {
-		  FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
-		  for (auto & param : this->params) {
-			  ftype->params.emplace_back(param->get_type());
-		  }
-		  for (auto & ret : this->returns) {
-			  ftype->returns.emplace_back(ret->get_type());
-		  }
-		  ftype->forall = std::move(forall);
-		  this->type = ftype;
-	  }
+	std::vector<ptr<TypeDecl>>&& forall,
+	std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
+	CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
+	std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
+: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
+	type_params(std::move(forall)), stmts( stmts ) {
+	FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
+	for (auto & param : this->params) {
+		ftype->params.emplace_back(param->get_type());
+	}
+	for (auto & ret : this->returns) {
+		ftype->returns.emplace_back(ret->get_type());
+	}
+	for (auto & tp : this->type_params) {
+		ftype->forall.emplace_back(new TypeInstType(tp->name, tp));
+	}
+	this->type = ftype;
+}
 
 
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Decl.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -132,4 +132,7 @@
 	std::vector< ptr<Expr> > withExprs;
 
+	std::vector<ptr<TypeDecl>> type_params;
+	std::vector<ptr<DeclWithType>> assertions;
+
 	FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
 		std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
@@ -154,5 +157,4 @@
 public:
 	ptr<Type> base;
-	std::vector<ptr<TypeDecl>> params;
 	std::vector<ptr<DeclWithType>> assertions;
 
@@ -160,5 +162,5 @@
 		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() {}
+	: Decl( loc, name, storage, spec ), base( b ), assertions() {}
 
 	/// Produces a name for the kind of alias
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Expr.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -206,40 +206,5 @@
 	assert( aggregate->result );
 
-	// Deep copy on result type avoids mutation on transitively multiply referenced object.
-	//
-	// Example, adapted from parts of builtins and bootloader:
-	//
-	// forall(dtype T)
-	// struct __Destructor {
-	//   T * object;
-	//   void (*dtor)(T *);
-	// };
-	//
-	// forall(dtype S)
-	// void foo(__Destructor(S) &d) {
-	//   if (d.dtor) {  // here
-	//   }
-	// }
-	//
-	// Let e be the "d.dtor" guard espression, which is MemberExpr after resolve.  Let d be the
-	// declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level
-	// declaration of __Destructor.  Consider the types e.result and d.type.  In the old AST, one
-	// is a clone of the other.  Ordinary new-AST use would set them up as a multiply-referenced
-	// object.
-	//
-	// e.result: PointerType
-	// .base: FunctionType
-	// .params.front(): ObjectDecl, the anonymous parameter of type T*
-	// .type: PointerType
-	// .base: TypeInstType
-	// let x = that
-	// let y = similar, except start from d.type
-	//
-	// Consider two code lines down, genericSubstitution(...).apply(result).
-	//
-	// Applying this chosen-candidate's type substitution means modifying x, substituting
-	// S for T.  This mutation should affect x and not y.
-
-	result = deepCopy(mem->get_type());
+	result = mem->get_type();
 
 	// substitute aggregate generic parameters into member type
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Expr.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -112,4 +112,5 @@
 
 		bool hasSlots() const { return data.resnSlots; }
+		bool hasParams() const { return data.inferParams; }
 
 		ResnSlots& resnSlots() {
Index: c/AST/ForallSubstitutionTable.cpp
===================================================================
--- src/AST/ForallSubstitutionTable.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ 	(revision )
@@ -1,54 +1,0 @@
-//
-// 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 "Copy.hpp"                // for shallowCopy
-#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 = shallowCopy( d );
-		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: c/AST/ForallSubstitutionTable.hpp
===================================================================
--- src/AST/ForallSubstitutionTable.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ 	(revision )
@@ -1,57 +1,0 @@
-//
-// 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: c/AST/ForallSubstitutor.hpp
===================================================================
--- src/AST/ForallSubstitutor.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ 	(revision )
@@ -1,70 +1,0 @@
-//
-// 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 );
-	}
-
-	template<typename node_t > 
-	std::vector<ptr<node_t>> operator() (const std::vector<ptr<node_t>> & o) {
-		std::vector<ptr<node_t>> n;
-		n.reserve(o.size());
-		for (const node_t * d : o) { n.emplace_back(d->accept(*visitor)); }
-		return n;
-	}
-	
-	/*
-
-	/// 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/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Fwd.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -139,8 +139,8 @@
 struct TranslationUnit;
 // TODO: Get from the TranslationUnit:
-extern Type * sizeType;
-extern FunctionDecl * dereferenceOperator;
-extern StructDecl   * dtorStruct;
-extern FunctionDecl * dtorStructDestroy;
+extern ptr<Type> sizeType;
+extern const FunctionDecl * dereferenceOperator;
+extern const StructDecl   * dtorStruct;
+extern const FunctionDecl * dtorStructDestroy;
 
 }
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Pass.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -34,6 +34,4 @@
 
 #include "AST/SymbolTable.hpp"
-
-#include "AST/ForallSubstitutionTable.hpp"
 
 // Private prelude header, needed for some of the magic tricks this class pulls off
@@ -66,5 +64,4 @@
 // | WithVisitorRef        - provides an pointer to the templated visitor wrapper
 // | WithSymbolTable       - provides symbol table functionality
-// | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation
 //
 // Other Special Members:
@@ -258,8 +255,4 @@
 	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
@@ -287,9 +280,9 @@
 	/// Internal RAII guard for forall substitutions
 	struct guard_forall_subs {
-		guard_forall_subs( Pass<core_t> & pass, const ParameterizedType * type )
+		guard_forall_subs( Pass<core_t> & pass, const FunctionType * type )
 		: pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); }
 		~guard_forall_subs()         { __pass::forall::leave(pass.core, 0, type ); }
 		Pass<core_t> & pass;
-		const ParameterizedType * type;
+		const FunctionType * type;
 	};
 
@@ -398,9 +391,4 @@
 };
 
-/// 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 b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Pass.impl.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -367,20 +367,4 @@
 	}
 
-
-	template< typename core_t >
-	template< typename node_t >
-	void ast::Pass< core_t >::mutate_forall( const node_t *& node ) {
-		if ( auto subs = __pass::forall::subs( core, 0 ) ) {
-			// tracking TypeDecl substitution, full clone
-			if ( node->forall.empty() ) return;
-
-			node_t * mut = __pass::mutate<core_t>( node );
-			mut->forall = subs->clone( node->forall, *this );
-			node = mut;
-		} else {
-			// not tracking TypeDecl substitution, just mutate
-			maybe_accept( node, &node_t::forall );
-		}
-	}
 }
 
@@ -504,9 +488,10 @@
 			__pass::symtab::addId( core, 0, func );
 			VISIT(
-				// parameter declarations are now directly here
+				// parameter declarations
 				maybe_accept( node, &FunctionDecl::params );
 				maybe_accept( node, &FunctionDecl::returns );
-				// foralls are still in function type
-				maybe_accept( node, &FunctionDecl::type );
+				// type params and assertions
+				maybe_accept( node, &FunctionDecl::type_params );
+				maybe_accept( node, &FunctionDecl::assertions );
 				// First remember that we are now within a function.
 				ValueGuard< bool > oldInFunction( inFunction );
@@ -609,5 +594,4 @@
 	VISIT({
 		guard_symtab guard { *this };
-		maybe_accept( node, &TypeDecl::params );
 		maybe_accept( node, &TypeDecl::base   );
 	})
@@ -638,5 +622,4 @@
 	VISIT({
 		guard_symtab guard { *this };
-		maybe_accept( node, &TypedefDecl::params );
 		maybe_accept( node, &TypedefDecl::base   );
 	})
@@ -1760,6 +1743,7 @@
 
 	VISIT({
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
+		// guard_forall_subs forall_guard { *this, node };
+		// mutate_forall( node );
+		maybe_accept( node, &FunctionType::assertions );
 		maybe_accept( node, &FunctionType::returns );
 		maybe_accept( node, &FunctionType::params  );
@@ -1779,6 +1763,4 @@
 	VISIT({
 		guard_symtab guard { *this };
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &StructInstType::params );
 	})
@@ -1797,6 +1779,4 @@
 	VISIT({
 		guard_symtab guard { *this };
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &UnionInstType::params );
 	})
@@ -1812,6 +1792,4 @@
 
 	VISIT({
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &EnumInstType::params );
 	})
@@ -1827,6 +1805,4 @@
 
 	VISIT({
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &TraitInstType::params );
 	})
@@ -1843,6 +1819,4 @@
 	VISIT(
 		{
-			guard_forall_subs forall_guard { *this, node };
-			mutate_forall( node );
 			maybe_accept( node, &TypeInstType::params );
 		}
@@ -1993,5 +1967,5 @@
 		{
 			bool mutated = false;
-			std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
+			std::unordered_map< ast::TypeInstType::TypeEnvKey, ast::ptr< ast::Type > > new_map;
 			for ( const auto & p : node->typeEnv ) {
 				guard_symtab guard { *this };
@@ -2006,20 +1980,4 @@
 			}
 		}
-
-		{
-			bool mutated = false;
-			std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
-			for ( const auto & p : node->varEnv ) {
-				guard_symtab guard { *this };
-				auto new_node = p.second->accept( *this );
-				if (new_node != p.second) mutated = true;
-				new_map.insert({ p.first, new_node });
-			}
-			if (mutated) {
-				auto new_node = __pass::mutate<core_t>( node );
-				new_node->varEnv.swap( new_map );
-				node = new_node;
-			}
-		}
 	)
 
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Pass.proto.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -396,5 +396,5 @@
 		// Some simple scoping rules
 		template<typename core_t>
-		static inline auto enter( core_t & core, int, const ast::ParameterizedType * type )
+		static inline auto enter( core_t & core, int, const ast::FunctionType * type )
 		-> decltype( core.subs, void() ) {
 			if ( ! type->forall.empty() ) core.subs.beginScope();
@@ -402,8 +402,8 @@
 
 		template<typename core_t>
-		static inline auto enter( core_t &, long, const ast::ParameterizedType * ) {}
-
-		template<typename core_t>
-		static inline auto leave( core_t & core, int, const ast::ParameterizedType * type )
+		static inline auto enter( core_t &, long, const ast::FunctionType * ) {}
+
+		template<typename core_t>
+		static inline auto leave( core_t & core, int, const ast::FunctionType * type )
 		-> decltype( core.subs, void() ) {
 			if ( ! type->forall.empty() ) { core.subs.endScope(); }
@@ -411,14 +411,5 @@
 
 		template<typename core_t>
-		static inline auto leave( core_t &, long, const ast::ParameterizedType * ) {}
-
-		// Get the substitution table, if present
-		template<typename core_t>
-		static inline auto subs( core_t & core, int ) -> decltype( &core.subs ) {
-			return &core.subs;
-		}
-
-		template<typename core_t>
-		static inline ast::ForallSubstitutionTable * subs( core_t &, long ) { return nullptr; }
+		static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
 
 		// Replaces a TypeInstType's base TypeDecl according to the table
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Print.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -146,9 +146,18 @@
 	}
 
-	void print( const ast::ParameterizedType::ForallList & forall ) {
+	void print( const ast::FunctionType::ForallList & forall ) {
 		if ( forall.empty() ) return;
 		os << "forall" << endl;
 		++indent;
 		printAll( forall );
+		os << indent;
+		--indent;
+	}
+
+	void print( const ast::FunctionType::AssertionList & assts ) {
+		if (assts.empty()) return;
+		os << "with assertions" << endl;
+		++indent;
+		printAll(assts);
 		os << indent;
 		--indent;
@@ -206,6 +215,5 @@
 	void preprint( const ast::NamedTypeDecl * node ) {
 		if ( ! node->name.empty() ) {
-			if( deterministic_output && isUnboundType(node->name) ) os << "[unbound]:";
-			else os << node->name << ": ";
+			os << node->name << ": ";
 		}
 
@@ -224,11 +232,4 @@
 		}
 
-		if ( ! node->params.empty() ) {
-			os << endl << indent << "... with parameters" << endl;
-			++indent;
-			printAll( node->params );
-			--indent;
-		}
-
 		if ( ! node->assertions.empty() ) {
 			os << endl << indent << "... with assertions" << endl;
@@ -266,11 +267,11 @@
 	}
 
-	void preprint( const ast::ParameterizedType * node ) {
+	void preprint( const ast::FunctionType * node ) {
 		print( node->forall );
+		print( node->assertions );
 		print( node->qualifiers );
 	}
 
 	void preprint( const ast::BaseInstType * node ) {
-		print( node->forall );
 		print( node->attributes );
 		print( node->qualifiers );
@@ -1383,5 +1384,5 @@
 	virtual const ast::Type * visit( const ast::TypeInstType * node ) override final {
 		preprint( node );
-		const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->name;
+		const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->typeString();
 		os << "instance of type " << _name
 		   << " (" << (node->kind == ast::TypeDecl::Ftype ? "" : "not ") << "function type)";
@@ -1510,15 +1511,7 @@
 		os << indent << "Types:" << endl;
 		for ( const auto& i : *node ) {
-			os << indent+1 << i.first << " -> ";
+			os << indent+1 << i.first.typeString() << " -> ";
 			indent += 2;
 			safe_print( i.second );
-			indent -= 2;
-			os << endl;
-		}
-		os << indent << "Non-types:" << endl;
-		for ( auto i = node->beginVar(); i != node->endVar(); ++i ) {
-			os << indent+1 << i->first << " -> ";
-			indent += 2;
-			safe_print( i->second );
 			indent -= 2;
 			os << endl;
Index: src/AST/SymbolTable.cpp
===================================================================
--- src/AST/SymbolTable.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/SymbolTable.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -414,5 +414,11 @@
 
 void SymbolTable::addFunction( const FunctionDecl * func ) {
-	addTypes( func->type->forall );
+	for (auto & td : func->type_params) {
+		addType(td);
+	}
+	for (auto & asst : func->assertions) {
+		addId(asst);
+	}
+	// addTypes( func->type->forall );
 	addIds( func->returns );
 	addIds( func->params );
Index: src/AST/TranslationUnit.hpp
===================================================================
--- src/AST/TranslationUnit.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/TranslationUnit.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -29,8 +29,8 @@
 		std::map< UniqueId, Decl * > idMap;
 
-		Type * sizeType;
-		FunctionDecl * dereference;
-		StructDecl * dtorStruct;
-		FunctionDecl * dtorDestroy;
+		const Type * sizeType;
+		const FunctionDecl * dereference;
+		const StructDecl * dtorStruct;
+		const FunctionDecl * dtorDestroy;
 	} global;
 };
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Type.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -21,5 +21,4 @@
 
 #include "Decl.hpp"
-#include "ForallSubstitutor.hpp" // for substituteForall
 #include "Init.hpp"
 #include "Common/utility.h"      // for copy, move
@@ -92,24 +91,5 @@
 // GENERATED END
 
-// --- ParameterizedType
-
-void ParameterizedType::initWithSub(
-	const ParameterizedType & o, Pass< ForallSubstitutor > & sub
-) {
-	forall = sub.core( 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.core( o.returns ); // apply to return and parameter types
-	params = sub.core( o.params );
-}
-
 namespace {
 	bool containsTtype( const std::vector<ptr<Type>> & l ) {
@@ -123,18 +103,4 @@
 bool FunctionType::isTtype() const {
 	return containsTtype( returns ) || containsTtype( params );
-}
-
-// --- BaseInstType
-
-void BaseInstType::initWithSub( const BaseInstType & o, Pass< ForallSubstitutor > & sub ) {
-	ParameterizedType::initWithSub( o, sub ); // initialize substitution
-	params = sub.core( o.params );            // apply to parameters
-}
-
-BaseInstType::BaseInstType( const BaseInstType & o )
-: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ),
-  hoistType( o.hoistType ) {
-	Pass< ForallSubstitutor > sub;
-	initWithSub( o, sub );
 }
 
@@ -177,13 +143,4 @@
 : BaseInstType( b->name, q, move(as) ), base( b ) {}
 
-// --- TypeInstType
-
-TypeInstType::TypeInstType( const TypeInstType & o )
-: BaseInstType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) {
-	Pass< ForallSubstitutor > sub;
-	initWithSub( o, sub );      // initialize substitution
-	base = sub.core( o.base );  // apply to base type
-}
-
 void TypeInstType::set_base( const TypeDecl * b ) {
 	base = b;
@@ -222,16 +179,5 @@
 		// TODO: once TypeInstType representation is updated, it should properly check
 		// if the context id is filled. this is a temporary hack for now
-		return isUnboundType(typeInst->name);
-	}
-	return false;
-}
-
-bool isUnboundType(const std::string & tname) {
-	// xxx - look for a type name produced by renameTyVars.
-
-	// TODO: once TypeInstType representation is updated, it should properly check
-	// if the context id is filled. this is a temporary hack for now
-	if (std::count(tname.begin(), tname.end(), '_') >= 3) {
-		return true;
+		return typeInst->formal_usage > 0;
 	}
 	return false;
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/Type.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -36,6 +36,4 @@
 
 template< typename T > class Pass;
-
-struct ForallSubstitutor;
 
 class Type : public Node {
@@ -267,39 +265,15 @@
 };
 
-/// 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>>;
-
-	ForallList forall;
-
-	ParameterizedType( ForallList&& fs = {}, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
-	: Type(q, std::move(as)), forall(std::move(fs)) {}
-
-	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:
-	virtual ParameterizedType * clone() const override = 0;
-	MUTATE_FRIEND
-};
-
 /// Function variable arguments flag
 enum ArgumentFlag { FixedArgs, VariableArgs };
 
 /// Type of a function `[R1, R2](*)(P1, P2, P3)`
-class FunctionType final : public ParameterizedType {
-public:
+class FunctionType final : public Type {
+public:
+	using ForallList = std::vector<ptr<TypeInstType>>;
+	using AssertionList = std::vector<ptr<VariableExpr>>;
+	ForallList forall;
+	AssertionList assertions;
+
 	std::vector<ptr<Type>> returns;
 	std::vector<ptr<Type>> params;
@@ -313,7 +287,7 @@
 
 	FunctionType( ArgumentFlag va = FixedArgs, CV::Qualifiers q = {} )
-	: ParameterizedType(q), returns(), params(), isVarArgs(va) {}
-
-	FunctionType( const FunctionType & o );
+	: Type(q), returns(), params(), isVarArgs(va) {}
+
+	FunctionType( const FunctionType & o ) = default;
 
 	/// true if either the parameters or return values contain a tttype
@@ -329,8 +303,5 @@
 
 /// base class for types that refer to types declared elsewhere (aggregates and typedefs)
-class BaseInstType : public ParameterizedType {
-protected:
-	/// Initializes forall and parameters based on substitutor
-	void initWithSub( const BaseInstType & o, Pass< ForallSubstitutor > & sub );
+class BaseInstType : public Type {
 public:
 	std::vector<ptr<Expr>> params;
@@ -340,12 +311,12 @@
 	BaseInstType(
 		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
-	: ParameterizedType(q, std::move(as)), params(), name(n) {}
+	: Type(q, std::move(as)), params(), name(n) {}
 
 	BaseInstType(
 		const std::string& n, std::vector<ptr<Expr>> && params,
 		CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
-	: ParameterizedType(q, std::move(as)), params(std::move(params)), name(n) {}
-
-	BaseInstType( const BaseInstType & o );
+	: Type(q, std::move(as)), params(std::move(params)), name(n) {}
+
+	BaseInstType( const BaseInstType & o ) = default;
 
 	/// Gets aggregate declaration this type refers to
@@ -423,5 +394,26 @@
 public:
 	readonly<TypeDecl> base;
+	// previously from renameTyVars; now directly use integer fields instead of synthesized strings
+	// a nonzero value of formal_usage indicates a formal type (only used in function type)
+	// a zero value of formal_usage indicates an actual type (referenced inside body of parametric structs and functions)
 	TypeDecl::Kind kind;
+	int formal_usage;
+	int expr_id;
+
+	// compact representation used for map lookups.
+	struct TypeEnvKey { 
+		const TypeDecl * base;
+		int formal_usage;
+		int expr_id;
+
+		TypeEnvKey() = default;
+		TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0): base(base), formal_usage(formal_usage), expr_id(expr_id) {}
+		TypeEnvKey(const TypeInstType & inst): base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
+		std::string typeString() const { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; }
+		bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
+
+	};
+
+	bool operator==(const TypeInstType & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
 
 	TypeInstType(
@@ -433,5 +425,8 @@
 	: BaseInstType( n, q, std::move(as) ), base(), kind( k ) {}
 
-	TypeInstType( const TypeInstType & o );
+	TypeInstType( const TypeInstType & o ) = default;
+
+	TypeInstType( const TypeEnvKey & key )
+	: BaseInstType(key.base->name), base(key.base), kind(key.base->kind), formal_usage(key.formal_usage), expr_id(key.expr_id) {}
 
 	/// sets `base`, updating `kind` correctly
@@ -444,4 +439,9 @@
 
 	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
+
+	std::string typeString() const { 
+		if (formal_usage > 0) return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + name; 
+		else return name;
+	}
 private:
 	TypeInstType * clone() const override { return new TypeInstType{ *this }; }
@@ -536,6 +536,18 @@
 
 bool isUnboundType(const Type * type);
-bool isUnboundType(const std::string & tname);
-
+
+}
+
+namespace std {
+	template<>
+	struct hash<typename ast::TypeInstType::TypeEnvKey> {
+		size_t operator() (const ast::TypeInstType::TypeEnvKey & x) const {
+			const size_t p = 1000007;
+			size_t res = reinterpret_cast<size_t>(x.base);
+			res = p * res + x.formal_usage;
+			res = p * res + x.expr_id;
+			return res;
+		} 
+	};
 }
 
Index: src/AST/TypeEnvironment.cpp
===================================================================
--- src/AST/TypeEnvironment.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/TypeEnvironment.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -52,5 +52,5 @@
 	for ( const auto & i : open ) {
 		if ( first ) { first = false; } else { out << ' '; }
-		out << i.first << "(" << i.second << ")";
+		out << i.first.typeString() << "(" << i.second << ")";
 	}
 }
@@ -62,6 +62,9 @@
 		if(first) first = false;
 		else out << " ";
-		if( deterministic_output && isUnboundType(var) ) out << "[unbound]";
-		else out << var;
+
+		if( deterministic_output ) out << "[unbound]";
+		else out << "_" << var.formal_usage << "_" << var.expr_id << "_";
+
+		out << var.base->name;
 	}
 	out << ")";
@@ -79,5 +82,5 @@
 }
 
-const EqvClass * TypeEnvironment::lookup( const std::string & var ) const {
+const EqvClass * TypeEnvironment::lookup( const TypeInstType::TypeEnvKey & var ) const {
 	for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) {
 		if ( i->vars.find( var ) != i->vars.end() ) return &*i;
@@ -105,6 +108,6 @@
 }
 
-void TypeEnvironment::add( const ParameterizedType::ForallList & tyDecls ) {
-	for ( const TypeDecl * tyDecl : tyDecls ) {
+void TypeEnvironment::add( const FunctionType::ForallList & tyDecls ) {
+	for ( auto & tyDecl : tyDecls ) {
 		env.emplace_back( tyDecl );
 	}
@@ -119,12 +122,14 @@
 void TypeEnvironment::writeToSubstitution( TypeSubstitution & sub ) const {
 	for ( const auto & clz : env ) {
-		std::string clzRep;
+		TypeInstType::TypeEnvKey clzRep;
+		bool first = true;
 		for ( const auto & var : clz.vars ) {
 			if ( clz.bound ) {
 				sub.add( var, clz.bound );
-			} else if ( clzRep.empty() ) {
+			} else if ( first ) {
 				clzRep = var;
+				first = false;
 			} else {
-				sub.add( var, new TypeInstType{ clzRep, clz.data.kind } );
+				sub.add( var, new TypeInstType{ clzRep } );
 			}
 		}
@@ -141,8 +146,8 @@
 	struct Occurs : public ast::WithVisitorRef<Occurs> {
 		bool result;
-		std::set< std::string > vars;
+		std::unordered_set< TypeInstType::TypeEnvKey > vars;
 		const TypeEnvironment & tenv;
 
-		Occurs( const std::string & var, const TypeEnvironment & env )
+		Occurs( const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env )
 		: result( false ), vars(), tenv( env ) {
 			if ( const EqvClass * clz = tenv.lookup( var ) ) {
@@ -154,7 +159,7 @@
 
 		void previsit( const TypeInstType * typeInst ) {
-			if ( vars.count( typeInst->name ) ) {
+			if ( vars.count( *typeInst ) ) {
 				result = true;
-			} else if ( const EqvClass * clz = tenv.lookup( typeInst->name ) ) {
+			} else if ( const EqvClass * clz = tenv.lookup( *typeInst ) ) {
 				if ( clz->bound ) {
 					clz->bound->accept( *visitor );
@@ -165,5 +170,5 @@
 
 	/// true if `var` occurs in `ty` under `env`
-	bool occurs( const Type * ty, const std::string & var, const TypeEnvironment & env ) {
+	bool occurs( const Type * ty, const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env ) {
 		Pass<Occurs> occur{ var, env };
 		maybe_accept( ty, occur );
@@ -280,10 +285,10 @@
 	// remove references from bound type, so that type variables can only bind to value types
 	ptr<Type> target = bindTo->stripReferences();
-	auto tyvar = open.find( typeInst->name );
+	auto tyvar = open.find( *typeInst );
 	assert( tyvar != open.end() );
 	if ( ! tyVarCompatible( tyvar->second, target ) ) return false;
-	if ( occurs( target, typeInst->name, *this ) ) return false;
-
-	auto it = internal_lookup( typeInst->name );
+	if ( occurs( target, *typeInst, *this ) ) return false;
+
+	auto it = internal_lookup( *typeInst );
 	if ( it != env.end() ) {
 		if ( it->bound ) {
@@ -308,5 +313,5 @@
 	} else {
 		env.emplace_back(
-			typeInst->name, target, widen.first && widen.second, data );
+			*typeInst, target, widen.first && widen.second, data );
 	}
 	return true;
@@ -318,6 +323,6 @@
 		WidenMode widen, const SymbolTable & symtab
 ) {
-	auto c1 = internal_lookup( var1->name );
-	auto c2 = internal_lookup( var2->name );
+	auto c1 = internal_lookup( *var1 );
+	auto c2 = internal_lookup( *var2 );
 
 	// exit early if variables already bound together
@@ -333,5 +338,5 @@
 	if ( c1 != env.end() ) {
 		if ( c1->bound ) {
-			if ( occurs( c1->bound, var2->name, *this ) ) return false;
+			if ( occurs( c1->bound, *var2, *this ) ) return false;
 			type1 = c1->bound;
 		}
@@ -340,5 +345,5 @@
 	if ( c2 != env.end() ) {
 		if ( c2->bound ) {
-			if ( occurs( c2->bound, var1->name, *this ) ) return false;
+			if ( occurs( c2->bound, *var1, *this ) ) return false;
 			type2 = c2->bound;
 		}
@@ -378,15 +383,15 @@
 	} else if ( c1 != env.end() ) {
 		// var2 unbound, add to env[c1]
-		c1->vars.emplace( var2->name );
+		c1->vars.emplace( *var2 );
 		c1->allowWidening = widen1;
 		c1->data.isComplete |= data.isComplete;
 	} else if ( c2 != env.end() ) {
 		// var1 unbound, add to env[c2]
-		c2->vars.emplace( var1->name );
+		c2->vars.emplace( *var1 );
 		c2->allowWidening = widen2;
 		c2->data.isComplete |= data.isComplete;
 	} else {
 		// neither var bound, create new class
-		env.emplace_back( var1->name, var2->name, widen1 && widen2, data );
+		env.emplace_back( *var1, *var2, widen1 && widen2, data );
 	}
 
@@ -452,5 +457,5 @@
 }
 
-TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const std::string & var ) {
+TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const TypeInstType::TypeEnvKey & var ) {
 	for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) {
 		if ( i->vars.count( var ) ) return i;
Index: src/AST/TypeEnvironment.hpp
===================================================================
--- src/AST/TypeEnvironment.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/TypeEnvironment.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -55,7 +55,7 @@
 /// recorded. More investigation is needed.
 struct AssertCompare {
-	bool operator()( const DeclWithType * d1, const DeclWithType * d2 ) const {
-		int cmp = d1->name.compare( d2->name );
-		return cmp < 0 || ( cmp == 0 && d1->get_type() < d2->get_type() );
+	bool operator()( const VariableExpr * d1, const VariableExpr * d2 ) const {
+		int cmp = d1->var->name.compare( d2->var->name );
+		return cmp < 0 || ( cmp == 0 && d1->result < d2->result );
 	}
 };
@@ -70,8 +70,8 @@
 
 /// Set of assertions pending satisfaction
-using AssertionSet = std::map< readonly<DeclWithType>, AssertionSetValue, AssertCompare >;
+using AssertionSet = std::map< const VariableExpr *, AssertionSetValue, AssertCompare >;
 
 /// Set of open variables
-using OpenVarSet = std::unordered_map< std::string, TypeDecl::Data >;
+using OpenVarSet = std::unordered_map< TypeInstType::TypeEnvKey, TypeDecl::Data >;
 
 /// Merges one set of open vars into another
@@ -89,5 +89,5 @@
 /// they bind to.
 struct EqvClass {
-	std::set< std::string > vars;
+	std::unordered_set< TypeInstType::TypeEnvKey > vars;
 	ptr<Type> bound;
 	bool allowWidening;
@@ -101,13 +101,13 @@
 
 	/// Singleton class constructor from TypeDecl
-	EqvClass( const TypeDecl * decl )
-	: vars{ decl->name }, bound(), allowWidening( true ), data( decl ) {}
+	EqvClass( const TypeInstType * inst )
+	: vars{ *inst }, bound(), allowWidening( true ), data( inst->base ) {}
 
 	/// Singleton class constructor from substitution
-	EqvClass( const std::string & v, const Type * b )
+	EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b )
 	: vars{ v }, bound( b ), allowWidening( false ), data( TypeDecl::Dtype, false ) {}
 
 	/// Single-var constructor (strips qualifiers from bound type)
-	EqvClass( const std::string & v, const Type * b, bool w, const TypeDecl::Data & d )
+	EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b, bool w, const TypeDecl::Data & d )
 	: vars{ v }, bound( b ), allowWidening( w ), data( d ) {
 		reset_qualifiers( bound );
@@ -115,5 +115,5 @@
 
 	/// Double-var constructor
-	EqvClass( const std::string & v, const std::string & u, bool w, const TypeDecl::Data & d )
+	EqvClass( const TypeInstType::TypeEnvKey & v, const TypeInstType::TypeEnvKey & u, bool w, const TypeDecl::Data & d )
 	: vars{ v, u }, bound(), allowWidening( w ), data( d ) {}
 
@@ -131,8 +131,8 @@
 public:
 	/// Finds the equivalence class containing a variable; nullptr for none such
-	const EqvClass * lookup( const std::string & var ) const;
+	const EqvClass * lookup( const TypeInstType::TypeEnvKey & var ) const;
 
 	/// Add a new equivalence class for each type variable
-	void add( const ParameterizedType::ForallList & tyDecls );
+	void add( const FunctionType::ForallList & tyDecls );
 
 	/// Add a new equivalence class for each branch of the substitution, checking for conflicts
@@ -207,5 +207,5 @@
 
 	/// Private lookup API; returns array index of string, or env.size() for not found
-	ClassList::iterator internal_lookup( const std::string & );
+	ClassList::iterator internal_lookup( const TypeInstType::TypeEnvKey & );
 };
 
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/TypeSubstitution.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -39,5 +39,4 @@
 void TypeSubstitution::initialize( const TypeSubstitution &src, TypeSubstitution &dest ) {
 	dest.typeEnv.clear();
-	dest.varEnv.clear();
 	dest.add( src );
 }
@@ -47,26 +46,23 @@
 		typeEnv[ i->first ] = i->second;
 	} // for
-	for ( VarEnvType::const_iterator i = other.varEnv.begin(); i != other.varEnv.end(); ++i ) {
-		varEnv[ i->first ] = i->second;
-	} // for
 }
 
-void TypeSubstitution::add( std::string formalType, const Type *actualType ) {
-	typeEnv[ formalType ] = actualType;
+void TypeSubstitution::add( const TypeInstType * formalType, const Type *actualType ) {
+	typeEnv[ *formalType ] = actualType;
 }
 
-void TypeSubstitution::addVar( std::string formalExpr, const Expr *actualExpr ) {
-	varEnv[ formalExpr ] = actualExpr;
+void TypeSubstitution::add( const TypeInstType::TypeEnvKey & key, const Type * actualType) {
+	typeEnv[ key ] = actualType;
 }
 
-void TypeSubstitution::remove( std::string formalType ) {
-	TypeEnvType::iterator i = typeEnv.find( formalType );
+void TypeSubstitution::remove( const TypeInstType * formalType ) {
+	TypeEnvType::iterator i = typeEnv.find( *formalType );
 	if ( i != typeEnv.end() ) {
-		typeEnv.erase( formalType );
+		typeEnv.erase( *formalType );
 	} // if
 }
 
-const Type *TypeSubstitution::lookup( std::string formalType ) const {
-	TypeEnvType::const_iterator i = typeEnv.find( formalType );
+const Type *TypeSubstitution::lookup( const TypeInstType * formalType ) const {
+	TypeEnvType::const_iterator i = typeEnv.find( *formalType );
 
 	// break on not in substitution set
@@ -75,11 +71,9 @@
 	// attempt to transitively follow TypeInstType links.
 	while ( const TypeInstType *actualType = i->second.as<TypeInstType>()) {
-		const std::string& typeName = actualType->name;
-
 		// break cycles in the transitive follow
-		if ( formalType == typeName ) break;
+		if ( *formalType == *actualType ) break;
 
 		// Look for the type this maps to, returning previous mapping if none-such
-		i = typeEnv.find( typeName );
+		i = typeEnv.find( *actualType );
 		if ( i == typeEnv.end() ) return actualType;
 	}
@@ -90,5 +84,5 @@
 
 bool TypeSubstitution::empty() const {
-	return typeEnv.empty() && varEnv.empty();
+	return typeEnv.empty();
 }
 
@@ -98,8 +92,10 @@
 		TypeSubstitution * newEnv;
 		EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
-		void previsit( TypeDecl * tyDecl ) {
+		void previsit( FunctionType * ftype ) {
 			// transfer known bindings for seen type variables
-			if ( const Type * t = env->lookup( tyDecl->name ) ) {
-				newEnv->add( tyDecl->name, t );
+			for (auto & formal : ftype->forall) {
+				if ( const Type * t = env->lookup( formal ) ) {
+					newEnv->add( formal, t );
+				}
 			}
 		}
@@ -130,8 +126,8 @@
 
 const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
-	BoundVarsType::const_iterator bound = boundVars.find( inst->name );
+	BoundVarsType::const_iterator bound = boundVars.find( *inst );
 	if ( bound != boundVars.end() ) return inst;
 
-	TypeEnvType::const_iterator i = sub.typeEnv.find( inst->name );
+	TypeEnvType::const_iterator i = sub.typeEnv.find( *inst );
 	if ( i == sub.typeEnv.end() ) {
 		return inst;
@@ -141,5 +137,5 @@
 		// TODO: investigate preventing type variables from being bound to themselves in the first place.
 		if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
-			if ( inst->name == replacement->name ) {
+			if ( *inst == *replacement ) {
 				return inst;
 			}
@@ -156,36 +152,24 @@
 }
 
-const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
-	VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
-	if ( i == sub.varEnv.end() ) {
-		return nameExpr;
-	} else {
-		subCount++;
-		return i->second;
-	} // if
-}
-
-void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
+void TypeSubstitution::Substituter::previsit( const FunctionType * ptype ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( const TypeDecl * tyvar : ptype->forall ) {
-				boundVars.insert( tyvar->name );
+		for ( auto & tyvar : ptype->forall ) {
+				boundVars.insert( *tyvar );
 		} // for
 	} // if
 }
 
+/*
 void TypeSubstitution::Substituter::handleAggregateType( const BaseInstType * type ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( const TypeDecl * tyvar : type->forall ) {
-			boundVars.insert( tyvar->name );
-		} // for
 		// bind type variables from generic type instantiations
 		if ( auto decl = type->aggr() ) {
 			if ( ! type->params.empty() ) {
 				for ( const TypeDecl * tyvar : decl->params ) {
-					boundVars.insert( tyvar->name );
+					boundVars.insert( *tyvar );
 				} // for
 			} // if
@@ -201,4 +185,5 @@
 	handleAggregateType( aggregateUseType );
 }
+*/
 
 } // namespace ast
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/TypeSubstitution.hpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -69,11 +69,10 @@
 	}
 
-	void add( std::string formalType, const Type *actualType );
+	void add( const TypeInstType * formalType, const Type *actualType );
+	void add( const TypeInstType::TypeEnvKey & key, const Type *actualType );
 	void add( const TypeSubstitution &other );
-	void remove( std::string formalType );
-	const Type *lookup( std::string formalType ) const;
+	void remove( const TypeInstType * formalType );
+	const Type *lookup( const TypeInstType * formalType ) const;
 	bool empty() const;
-
-	void addVar( std::string formalExpr, const Expr *actualExpr );
 
 	template< typename FormalIterator, typename ActualIterator >
@@ -101,8 +100,6 @@
 	friend class Pass;
 
-	typedef std::unordered_map< std::string, ptr<Type> > TypeEnvType;
-	typedef std::unordered_map< std::string, ptr<Expr> > VarEnvType;
+	typedef std::unordered_map< TypeInstType::TypeEnvKey, ptr<Type> > TypeEnvType;
 	TypeEnvType typeEnv;
-	VarEnvType varEnv;
 
   public:
@@ -113,10 +110,7 @@
 	auto   end() const -> decltype( typeEnv.  end() ) { return typeEnv.  end(); }
 
-	auto beginVar()       -> decltype( varEnv.begin() ) { return varEnv.begin(); }
-	auto   endVar()       -> decltype( varEnv.  end() ) { return varEnv.  end(); }
-	auto beginVar() const -> decltype( varEnv.begin() ) { return varEnv.begin(); }
-	auto   endVar() const -> decltype( varEnv.  end() ) { return varEnv.  end(); }
 };
 
+// this is the only place where type parameters outside a function formal may be substituted.
 template< typename FormalIterator, typename ActualIterator >
 void TypeSubstitution::add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
@@ -129,5 +123,5 @@
 			if ( const TypeExpr *actual = actualIt->template as<TypeExpr>() ) {
 				if ( formal->name != "" ) {
-					typeEnv[ formal->name ] = actual->type;
+					typeEnv[ formal ] = actual->type;
 				} // if
 			} else {
@@ -135,11 +129,10 @@
 			} // if
 		} else {
-			// TODO: type check the formal and actual parameters
-			if ( (*formalIt)->name != "" ) {
-				varEnv[ (*formalIt)->name ] = *actualIt;
-			} // if
+			
 		} // if
 	} // for
 }
+
+
 
 template< typename FormalIterator, typename ActualIterator >
@@ -147,4 +140,5 @@
 	add( formalBegin, formalEnd, actualBegin );
 }
+
 
 } // namespace ast
@@ -164,18 +158,17 @@
 
 		const Type * postvisit( const TypeInstType * aggregateUseType );
-		const Expr * postvisit( const NameExpr * nameExpr );
 
 		/// Records type variable bindings from forall-statements
-		void previsit( const ParameterizedType * type );
+		void previsit( const FunctionType * type );
 		/// Records type variable bindings from forall-statements and instantiations of generic types
-		void handleAggregateType( const BaseInstType * type );
+		// void handleAggregateType( const BaseInstType * type );
 
-		void previsit( const StructInstType * aggregateUseType );
-		void previsit( const UnionInstType * aggregateUseType );
+		// void previsit( const StructInstType * aggregateUseType );
+		// void previsit( const UnionInstType * aggregateUseType );
 
 		const TypeSubstitution & sub;
 		int subCount = 0;
 		bool freeOnly;
-		typedef std::unordered_set< std::string > BoundVarsType;
+		typedef std::unordered_set< TypeInstType::TypeEnvKey > BoundVarsType;
 		BoundVarsType boundVars;
 
Index: src/AST/module.mk
===================================================================
--- src/AST/module.mk	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/AST/module.mk	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -33,7 +33,4 @@
 	AST/Expr.cpp \
 	AST/Expr.hpp \
-	AST/ForallSubstitutionTable.cpp \
-	AST/ForallSubstitutionTable.hpp \
-	AST/ForallSubstitutor.hpp \
 	AST/FunctionSpec.hpp \
 	AST/Fwd.hpp \
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/Common/PassVisitor.impl.h	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -835,5 +835,4 @@
 	{
 		auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
-		maybeAccept_impl( node->parameters, *this );
 		maybeAccept_impl( node->base      , *this );
 	}
@@ -858,5 +857,4 @@
 	{
 		auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
-		maybeAccept_impl( node->parameters, *this );
 		maybeAccept_impl( node->base      , *this );
 	}
@@ -880,5 +878,4 @@
 	{
 		auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
-		maybeMutate_impl( node->parameters, *this );
 		maybeMutate_impl( node->base      , *this );
 	}
@@ -904,5 +901,4 @@
 	{
 		auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
-		maybeAccept_impl( node->parameters, *this );
 		maybeAccept_impl( node->base      , *this );
 	}
@@ -921,5 +917,4 @@
 	{
 		auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
-		maybeAccept_impl( node->parameters, *this );
 		maybeAccept_impl( node->base      , *this );
 	}
@@ -938,5 +933,4 @@
 	{
 		auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
-		maybeMutate_impl( node->parameters, *this );
 		maybeMutate_impl( node->base      , *this );
 	}
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/GenPoly/GenPoly.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -115,5 +115,5 @@
 		if (!env) return type;
 		if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) {
-			auto newType = env->lookup(typeInst->name);
+			auto newType = env->lookup(typeInst);
 			if (newType) return newType;
 		}
@@ -172,5 +172,5 @@
 
 		if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
-			return tyVars.find(typeInst->name) != tyVars.end() ? type : nullptr;
+			return tyVars.find(typeInst->typeString()) != tyVars.end() ? type : nullptr;
 		} else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
 			return isPolyType( arrayType->base, env );
@@ -552,6 +552,6 @@
 	}
 
-	void addToTyVarMap( const ast::TypeDecl * tyVar, TyVarMap & tyVarMap) {
-		tyVarMap.insert(tyVar->name, convData(ast::TypeDecl::Data{tyVar}));
+	void addToTyVarMap( const ast::TypeInstType * tyVar, TyVarMap & tyVarMap) {
+		tyVarMap.insert(tyVar->typeString(), convData(ast::TypeDecl::Data{tyVar->base}));
 	}
 
@@ -567,5 +567,5 @@
 
 	void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap) {
-		if (auto ptype = dynamic_cast<const ast::ParameterizedType *>(type)) {
+		if (auto ptype = dynamic_cast<const ast::FunctionType *>(type)) {
  			for (auto & tyVar : ptype->forall) {
 				assert (tyVar);
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/Parser/TypeData.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -900,5 +900,4 @@
 		ret = new TypeDecl( name, scs, typebuild( td->base ), TypeDecl::Dtype, true );
 	} // if
-	buildList( td->symbolic.params, ret->get_parameters() );
 	buildList( td->symbolic.assertions, ret->get_assertions() );
 	ret->base->attributes.splice( ret->base->attributes.end(), attributes );
Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/AdjustExprType.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -133,5 +133,5 @@
 		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 ) ) {
+			if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) {
 				if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
 					return new ast::PointerType{ inst };
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -212,7 +212,5 @@
 		// mark type variable and specialization cost of forall clause
 		convCost.incVar( function->forall.size() );
-		for ( const ast::TypeDecl * td : function->forall ) {
-			convCost.decSpec( td->assertions.size() );
-		}
+		convCost.decSpec( function->assertions.size() );
 
 		return convCost;
@@ -220,12 +218,12 @@
 
 	void makeUnifiableVars(
-		const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars,
+		const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
 		ast::AssertionSet & need
 	) {
-		for ( const ast::TypeDecl * tyvar : type->forall ) {
-			unifiableVars[ tyvar->name ] = ast::TypeDecl::Data{ tyvar };
-			for ( const ast::DeclWithType * assn : tyvar->assertions ) {
-				need[ assn ].isUsed = true;
-			}
+		for ( auto & tyvar : type->forall ) {
+			unifiableVars[ *tyvar ] = ast::TypeDecl::Data{ tyvar->base };
+		}
+		for ( auto & assn : type->assertions ) {
+			need[ assn ].isUsed = true;
 		}
 	}
@@ -953,5 +951,5 @@
 						auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
 					) {
-						if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
+						if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
 							if ( auto function = clz->bound.as< ast::FunctionType >() ) {
 								CandidateRef newFunc{ new Candidate{ *func } };
@@ -1077,5 +1075,5 @@
 			assert( toType );
 			toType = resolveTypeof( toType, symtab );
-			toType = SymTab::validateType( castExpr->location, toType, symtab );
+			// toType = SymTab::validateType( castExpr->location, toType, symtab );
 			toType = adjustExprType( toType, tenv, symtab );
 
@@ -1162,5 +1160,5 @@
 
 					if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
-						auto td = cand->env.lookup(insttype->name);
+						auto td = cand->env.lookup(*insttype);
 						if(!td) { continue; }
 						expr = td->bound.get();
@@ -1568,5 +1566,5 @@
 				// calculate target type
 				const ast::Type * toType = resolveTypeof( initAlt.type, symtab );
-				toType = SymTab::validateType( initExpr->location, toType, symtab );
+				// toType = SymTab::validateType( initExpr->location, toType, symtab );
 				toType = adjustExprType( toType, tenv, symtab );
 				// The call to find must occur inside this loop, otherwise polymorphic return
Index: src/ResolvExpr/CastCost.cc
===================================================================
--- src/ResolvExpr/CastCost.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/CastCost.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -165,5 +165,5 @@
 				} else {
 					ast::TypeEnvironment newEnv{ env };
-					if ( auto wParams = pointerType->base.as< ast::ParameterizedType >() ) {
+					if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) {
 						newEnv.add( wParams->forall );
 					}
@@ -202,5 +202,5 @@
 ) {
 	if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( const ast::EqvClass * eqvClass = env.lookup( typeInst->name ) ) {
+		if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) {
 			// check cast cost against bound type, if present
 			if ( eqvClass->bound ) {
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/CommonType.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -713,5 +713,5 @@
 			const ast::Type * base = oPtr->base;
 			if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) {
-				auto entry = open.find( var->name );
+				auto entry = open.find( *var );
 				if ( entry != open.end() ) {
 					ast::AssertionSet need, have;
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/ConversionCost.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -498,5 +498,5 @@
 ) {
 	if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
+		if ( const ast::EqvClass * eqv = env.lookup( *inst ) ) {
 			if ( eqv->bound ) {
 				return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
@@ -675,9 +675,9 @@
 
 void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
-	if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
+	if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) {
 		cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
 	} else if ( const ast::TypeInstType * dstAsInst =
 			dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( typeInstType->name == dstAsInst->name ) {
+		if ( *typeInstType == *dstAsInst ) {
 			cost = Cost::zero;
 		}
Index: src/ResolvExpr/FindOpenVars.cc
===================================================================
--- src/ResolvExpr/FindOpenVars.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/FindOpenVars.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -112,16 +112,16 @@
 				// mark open/closed variables
 				if ( nextIsOpen ) {
-					for ( const ast::TypeDecl * decl : type->forall ) {
-						open[ decl->name ] = ast::TypeDecl::Data{ decl };
-						for ( const ast::DeclWithType * assert : decl->assertions ) {
-							need[ assert ].isUsed = false;
-						}
+					for ( auto & decl : type->forall ) {
+						open[ *decl ] = ast::TypeDecl::Data{ decl->base };
+					}
+					for ( auto & assert : type->assertions ) {
+						need[ assert ].isUsed = false;
 					}
 				} else {
-					for ( const ast::TypeDecl * decl : type->forall ) {
-						closed[ decl->name ] = ast::TypeDecl::Data{ decl };
-						for ( const ast::DeclWithType * assert : decl->assertions ) {
-							have[ assert ].isUsed = false;
-						}
+					for ( auto & decl : type->forall ) {
+						closed[ *decl ] = ast::TypeDecl::Data{ decl->base };	
+					}
+					for ( auto & assert : type->assertions ) {
+						have[ assert ].isUsed = false;
 					}
 				}
Index: src/ResolvExpr/PolyCost.cc
===================================================================
--- src/ResolvExpr/PolyCost.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/PolyCost.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -68,5 +68,5 @@
 
 	void previsit( const ast::TypeInstType * type ) {
-		if ( const ast::EqvClass * eqv = env_.lookup( type->name ) ) /* && */ if ( eqv->bound ) {
+		if ( const ast::EqvClass * eqv = env_.lookup( *type ) ) /* && */ if ( eqv->bound ) {
 			if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
 				if ( symtab.lookupType( otherType->name ) ) {
Index: src/ResolvExpr/PtrsAssignable.cc
===================================================================
--- src/ResolvExpr/PtrsAssignable.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/PtrsAssignable.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -134,5 +134,5 @@
 	}
 	void postvisit( const ast::TypeInstType * inst ) {
-		if ( const ast::EqvClass * eqv = typeEnv.lookup( inst->name ) ) {
+		if ( const ast::EqvClass * eqv = typeEnv.lookup( *inst ) ) {
 			if ( eqv->bound ) {
 				// T * = S * for any S depends on the type bound to T
@@ -146,5 +146,5 @@
 		const ast::TypeEnvironment & env ) {
 	if ( const ast::TypeInstType * dstAsInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( const ast::EqvClass * eqv = env.lookup( dstAsInst->name ) ) {
+		if ( const ast::EqvClass * eqv = env.lookup( *dstAsInst ) ) {
 			return ptrsAssignable( src, eqv->bound, env );
 		}
Index: src/ResolvExpr/PtrsCastable.cc
===================================================================
--- src/ResolvExpr/PtrsCastable.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/PtrsCastable.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -180,5 +180,5 @@
 					}
 				}
-			} else if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
+			} else if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
 				if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
 					return -1;
@@ -283,5 +283,5 @@
 ) {
 	if ( auto inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
+		if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
 			return ptrsAssignable( src, eqvClass->bound, env );
 		}
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/RenameVars.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -19,5 +19,4 @@
 #include <utility>                 // for pair
 
-#include "AST/ForallSubstitutionTable.hpp"
 #include "AST/Pass.hpp"
 #include "AST/Type.hpp"
@@ -39,8 +38,10 @@
 		int level = 0;
 		int resetCount = 0;
+
+		int next_expr_id = 1;
+		int next_usage_id = 1;
 		ScopedMap< std::string, std::string > nameMap;
+		ScopedMap< std::string, ast::TypeInstType::TypeEnvKey > idMap;
 	public:
-		ast::ForallSubstitutionTable subs;
-
 		void reset() {
 			level = 0;
@@ -53,4 +54,8 @@
 				type->name = it->second;
 			}
+		}
+
+		void nextUsage() {
+			++next_usage_id;
 		}
 
@@ -78,13 +83,13 @@
 
 		const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
-			// re-linking of base type handled by WithForallSubstitutor
-
 			// rename
-			auto it = nameMap.find( type->name );
-			if ( it != nameMap.end() ) {
-				// 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;
+			auto it = idMap.find( type->name );
+			if ( it != idMap.end() ) {
+				// unconditionally mutate because map will *always* have different name
+				ast::TypeInstType * mut = ast::shallowCopy( type );
+				// reconcile base node since some copies might have been made
+				mut->base = it->second.base;
+				mut->formal_usage = it->second.formal_usage;
+				mut->expr_id = it->second.expr_id;
 	            type = mut;
 			}
@@ -93,34 +98,38 @@
 		}
 
-		template<typename NodeT>
-		const NodeT * openLevel( const NodeT * type ) {
+		const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
 			if ( type->forall.empty() ) return type;
-
-			nameMap.beginScope();
+			idMap.beginScope();
 
 			// 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;
-		}
-
-		void closeLevel( const ast::ParameterizedType * type ) {
+			auto mutType = ast::shallowCopy( type );
+			// assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
+			for ( auto & td : mutType->forall ) {
+				auto mut = ast::shallowCopy( td.get() );
+				// assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
+
+				if (mode == GEN_EXPR_ID) {
+					mut->expr_id = next_expr_id;
+					mut->formal_usage = -1;
+					++next_expr_id;
+				}
+				else if (mode == GEN_USAGE) {
+					assertf(mut->expr_id, "unfilled expression id in generating candidate type");
+					mut->formal_usage = next_usage_id;
+				}
+				else {
+					assert(false);
+				}
+				idMap[ td->name ] = ast::TypeInstType::TypeEnvKey(*mut);
+				
+				td = mut;
+			}
+
+			return mutType;
+		}
+
+		void closeLevel( const ast::FunctionType * type ) {
 			if ( type->forall.empty() ) return;
-
-			nameMap.endScope();
+			idMap.endScope();
 		}
 	};
@@ -142,11 +151,12 @@
 	};
 
-	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;
+	struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
+		RenameMode mode;
 
 		const ast::FunctionType * previsit( const ast::FunctionType * type ) {
-			return renaming.openLevel( type );
-		}
+			return renaming.openLevel( type, mode );
+		}
+
+		/*
 		const ast::StructInstType * previsit( const ast::StructInstType * type ) {
 			return renaming.openLevel( type );
@@ -158,8 +168,11 @@
 			return renaming.openLevel( type );
 		}
+		*/
+
 		const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
-			return renaming.rename( renaming.openLevel( type ) );
-		}
-		void postvisit( const ast::ParameterizedType * type ) {
+			if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type
+			return renaming.rename( type );
+		}
+		void postvisit( const ast::FunctionType * type ) {
 			renaming.closeLevel( type );
 		}
@@ -173,9 +186,12 @@
 }
 
-const ast::Type * renameTyVars( const ast::Type * t ) {
-	ast::Type *tc = ast::deepCopy(t);
+const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode ) {
+	// ast::Type *tc = ast::deepCopy(t);
 	ast::Pass<RenameVars_new> renamer;
-//	return t->accept( renamer );
-	return tc->accept( renamer );
+	renamer.core.mode = mode;
+	if (mode == GEN_USAGE) {
+		renaming.nextUsage();
+	}
+	return t->accept( renamer );
 }
 
Index: src/ResolvExpr/RenameVars.h
===================================================================
--- src/ResolvExpr/RenameVars.h	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/RenameVars.h	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -30,8 +30,15 @@
 	/// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
 	void renameTyVars( Type * );
-	const ast::Type * renameTyVars( const ast::Type * );
+
+	enum RenameMode {
+		GEN_USAGE, // for type in VariableExpr
+		GEN_EXPR_ID // for type in decl
+	};
+	const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE );
 
 	/// resets internal state of renamer to avoid overflow
 	void resetTyVarRenaming();
+
+	
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -15,4 +15,5 @@
 
 #include "ResolveTypeof.h"
+#include "RenameVars.h"
 
 #include <cassert>               // for assert
@@ -218,4 +219,5 @@
 			mutDecl->mangleName = Mangle::mangle(mutDecl); // do not mangle unnamed variables
 		
+		mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
 		mutDecl->isTypeFixed = true;
 		return mutDecl;
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/Resolver.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -968,5 +968,5 @@
 	namespace {
 		/// Finds deleted expressions in an expression tree
-		struct DeleteFinder_new final : public ast::WithShortCircuiting {
+		struct DeleteFinder_new final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder_new> {
 			const ast::DeletedExpr * result = nullptr;
 
@@ -976,10 +976,14 @@
 			}
 
-			void previsit( const ast::Expr * ) {
+			void previsit( const ast::Expr * expr ) {
 				if ( result ) { visit_children = false; }
+				if (expr->inferred.hasParams()) {
+					for (auto & imp : expr->inferred.inferParams() ) {
+						imp.second.expr->accept(*visitor);
+					}
+				}
 			}
 		};
 	} // anonymous namespace
-
 	/// Check if this expression is or includes a deleted expression
 	const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
@@ -1370,15 +1374,17 @@
 			}
 
-			// handle assertions. (seems deep)
+			// handle assertions
 
 			symtab.enterScope();
-			for (auto & typeParam : mutType->forall) {
-				auto mutParam = typeParam.get_and_mutate();
-				symtab.addType(mutParam);
-				for (auto & asst : mutParam->assertions) {
-					asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
-					symtab.addId(asst);
-				}
-				typeParam = mutParam;
+			mutType->forall.clear();
+			mutType->assertions.clear();
+			for (auto & typeParam : mutDecl->type_params) {
+				symtab.addType(typeParam);
+				mutType->forall.emplace_back(new ast::TypeInstType(typeParam->name, typeParam));
+			}
+			for (auto & asst : mutDecl->assertions) {
+				asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
+				symtab.addId(asst);
+				mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
 			}
 
@@ -1402,4 +1408,6 @@
 			mutType->returns = std::move(returnTypes);
 
+			auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
+
 			std::list<ast::ptr<ast::Stmt>> newStmts;
 			resolveWithExprs (mutDecl->withExprs, newStmts);
@@ -1413,4 +1421,5 @@
 			symtab.leaveScope();
 
+			mutDecl->type = renamedType;
 			mutDecl->mangleName = Mangle::mangle(mutDecl);
 			mutDecl->isTypeFixed = true;
Index: src/ResolvExpr/SatisfyAssertions.cpp
===================================================================
--- src/ResolvExpr/SatisfyAssertions.cpp	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/SatisfyAssertions.cpp	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -69,5 +69,5 @@
 	/// Reference to a single deferred item
 	struct DeferRef {
-		const ast::DeclWithType * decl;
+		const ast::VariableExpr * expr;
 		const ast::AssertionSetValue & info;
 		const AssnCandidate & match;
@@ -77,11 +77,11 @@
 	/// Acts like an indexed list of DeferRef
 	struct DeferItem {
-		const ast::DeclWithType * decl;
+		const ast::VariableExpr * expr;
 		const ast::AssertionSetValue & info;
 		AssnCandidateList matches;
 
 		DeferItem( 
-			const ast::DeclWithType * d, const ast::AssertionSetValue & i, AssnCandidateList && ms )
-		: decl( d ), info( i ), matches( std::move( ms ) ) {}
+			const ast::VariableExpr * d, const ast::AssertionSetValue & i, AssnCandidateList && ms )
+		: expr( d ), info( i ), matches( std::move( ms ) ) {}
 
 		bool empty() const { return matches.empty(); }
@@ -89,5 +89,5 @@
 		AssnCandidateList::size_type size() const { return matches.size(); }
 
-		DeferRef operator[] ( unsigned i ) const { return { decl, info, matches[i] }; }
+		DeferRef operator[] ( unsigned i ) const { return { expr, info, matches[i] }; }
 	};
 
@@ -138,5 +138,5 @@
 	void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) {
 		for ( auto & i : have ) {
-			if ( i.second.isUsed ) { symtab.addId( i.first ); }
+			if ( i.second.isUsed ) { symtab.addId( i.first->var ); }
 		}
 	}
@@ -144,5 +144,5 @@
 	/// Binds a single assertion, updating satisfaction state
 	void bindAssertion( 
-		const ast::DeclWithType * decl, const ast::AssertionSetValue & info, CandidateRef & cand, 
+		const ast::VariableExpr * expr, const ast::AssertionSetValue & info, CandidateRef & cand, 
 		AssnCandidate & match, InferCache & inferred
 	) {
@@ -156,6 +156,6 @@
 
 		// place newly-inferred assertion in proper location in cache
-		inferred[ info.resnSlot ][ decl->uniqueId ] = ast::ParamEntry{
-			candidate->uniqueId, candidate, match.adjType, decl->get_type(), varExpr };
+		inferred[ info.resnSlot ][ expr->var->uniqueId ] = ast::ParamEntry{
+			candidate->uniqueId, candidate, match.adjType, expr->result, varExpr };
 	}
 
@@ -169,8 +169,8 @@
 
 		std::vector<ast::SymbolTable::IdData> candidates;
-		auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->name);
+		auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->var->name);
 		if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
 			// prefilter special decls by argument type, if already known
-			ast::ptr<ast::Type> thisArgType = strict_dynamic_cast<const ast::PointerType *>(assn.first->get_type())->base
+			ast::ptr<ast::Type> thisArgType = assn.first->result.strict_as<ast::PointerType>()->base
 				.strict_as<ast::FunctionType>()->params[0]
 				.strict_as<ast::ReferenceType>()->base;
@@ -184,5 +184,5 @@
 		}
 		else {
-			candidates = sat.symtab.lookupId(assn.first->name);
+			candidates = sat.symtab.lookupId(assn.first->var->name);
 		}
 		for ( const ast::SymbolTable::IdData & cdata : candidates ) {
@@ -194,5 +194,5 @@
 			// if we should implement the same rule here
 			// (i.e. error if unique best match is deleted)
-			if (candidate->isDeleted) continue;
+			if (candidate->isDeleted && candidate->linkage == ast::Linkage::AutoGen) continue;
 
 			// build independent unification context for candidate
@@ -200,5 +200,5 @@
 			ast::TypeEnvironment newEnv{ sat.cand->env };
 			ast::OpenVarSet newOpen{ sat.cand->open };
-			ast::ptr< ast::Type > toType = assn.first->get_type();
+			ast::ptr< ast::Type > toType = assn.first->result;
 			ast::ptr< ast::Type > adjType = 
 				renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ) );
@@ -337,5 +337,5 @@
 					// compute conversion cost from satisfying decl to assertion
 					cost += computeConversionCost(
-						assn.match.adjType, assn.decl->get_type(), false, symtab, env );
+						assn.match.adjType, assn.expr->result, false, symtab, env );
 
 					// mark vars+specialization on function-type assertions
@@ -350,7 +350,5 @@
 					cost.incVar( func->forall.size() );
 
-					for ( const ast::TypeDecl * td : func->forall ) {
-						cost.decSpec( td->assertions.size() );
-					}
+					cost.decSpec( func->assertions.size() );
 				}
 			}
@@ -451,5 +449,5 @@
 				ss << (tabs-1) << "Too many non-unique satisfying assignments for assertions:\n";
 				for ( const auto & d : sat.deferred ) {
-					ast::print( ss, d.decl, tabs );
+					ast::print( ss, d.expr, tabs );
 				}
 
@@ -469,5 +467,5 @@
 					ss << (tabs-1) << "No mutually-compatible satisfaction for assertions:\n";
 					for ( const auto& d : sat.deferred ) {
-						ast::print( ss, d.decl, tabs );
+						ast::print( ss, d.expr, tabs );
 					}
 
@@ -501,5 +499,5 @@
 						nextNewNeed.insert( match.need.begin(), match.need.end() );
 
-						bindAssertion( r.decl, r.info, nextCand, match, nextInferred );
+						bindAssertion( r.expr, r.info, nextCand, match, nextInferred );
 					}
 
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/ResolvExpr/Unify.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -773,5 +773,5 @@
 
 			const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
-				if ( const ast::EqvClass * clz = tenv.lookup( typeInst->name ) ) {
+				if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
 					// expand ttype parameter into its actual type
 					if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
@@ -888,5 +888,5 @@
 		}
 
-		static void markAssertionSet( ast::AssertionSet & assns, const ast::DeclWithType * assn ) {
+		static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
 			auto i = assns.find( assn );
 			if ( i != assns.end() ) {
@@ -898,11 +898,9 @@
 		static void markAssertions(
 			ast::AssertionSet & assn1, ast::AssertionSet & assn2,
-			const ast::ParameterizedType * type
+			const ast::FunctionType * type
 		) {
-			for ( const auto & tyvar : type->forall ) {
-				for ( const ast::DeclWithType * assert : tyvar->assertions ) {
-					markAssertionSet( assn1, assert );
-					markAssertionSet( assn2, assert );
-				}
+			for ( auto & assert : type->assertions ) {
+				markAssertionSet( assn1, assert );
+				markAssertionSet( assn2, assert );
 			}
 		}
@@ -1030,5 +1028,5 @@
 
 		void postvisit( const ast::TypeInstType * typeInst ) {
-			assert( open.find( typeInst->name ) == open.end() );
+			assert( open.find( *typeInst ) == open.end() );
 			handleRefType( typeInst, type2 );
 		}
@@ -1171,6 +1169,6 @@
 		auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
 		ast::OpenVarSet::const_iterator
-			entry1 = var1 ? open.find( var1->name ) : open.end(),
-			entry2 = var2 ? open.find( var2->name ) : open.end();
+			entry1 = var1 ? open.find( *var1 ) : open.end(),
+			entry2 = var2 ? open.find( *var2 ) : open.end();
 		bool isopen1 = entry1 != open.end();
 		bool isopen2 = entry2 != open.end();
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/SymTab/Mangler.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -666,10 +666,10 @@
 			// skip if not including qualifiers
 			if ( typeMode ) return;
-			if ( auto ptype = dynamic_cast< const ast::ParameterizedType * >(type) ) {
+			if ( auto ptype = dynamic_cast< const ast::FunctionType * >(type) ) {
 				if ( ! ptype->forall.empty() ) {
 					std::list< std::string > assertionNames;
 					int dcount = 0, fcount = 0, vcount = 0, acount = 0;
 					mangleName += Encoding::forall;
-					for ( const ast::TypeDecl * decl : ptype->forall ) {
+					for ( auto & decl : ptype->forall ) {
 						switch ( decl->kind ) {
 						case ast::TypeDecl::Kind::Dtype:
@@ -686,11 +686,11 @@
 						} // switch
 						varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
-						for ( const ast::DeclWithType * assert : decl->assertions ) {
-							ast::Pass<Mangler_new> sub_mangler(
-								mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
-							assert->accept( sub_mangler );
-							assertionNames.push_back( sub_mangler.core.get_mangleName() );
-							acount++;
-						} // for
+					} // for
+					for ( auto & assert : ptype->assertions ) {
+						ast::Pass<Mangler_new> sub_mangler(
+							mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
+						assert->var->accept( sub_mangler );
+						assertionNames.push_back( sub_mangler.core.get_mangleName() );
+						acount++;
 					} // for
 					mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/SymTab/Validate.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -1463,4 +1463,6 @@
 	}
 
+	/*
+
 	/// Associates forward declarations of aggregates with their definitions
 	class LinkReferenceToTypes_new final
@@ -1793,5 +1795,5 @@
 		static const node_t * forallFixer(
 			const CodeLocation & loc, const node_t * node,
-			ast::ParameterizedType::ForallList parent_t::* forallField
+			ast::FunctionType::ForallList parent_t::* forallField
 		) {
 			for ( unsigned i = 0; i < (node->* forallField).size(); ++i ) {
@@ -1844,6 +1846,8 @@
 		}
 	};
+	*/
 } // anonymous namespace
 
+/*
 const ast::Type * validateType(
 		const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ) {
@@ -1854,4 +1858,5 @@
 	return type->accept( lrt )->accept( fpd );
 }
+*/
 
 } // namespace SymTab
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/SynTree/Declaration.h	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -181,5 +181,4 @@
   public:
 	Type * base;
-	std::list< TypeDecl * > parameters;
 	std::list< DeclarationWithType * > assertions;
 
@@ -190,5 +189,4 @@
 	Type * get_base() const { return base; }
 	void set_base( Type * newValue ) { base = newValue; }
-	std::list< TypeDecl* > & get_parameters() { return parameters; }
 	std::list< DeclarationWithType * >& get_assertions() { return assertions; }
 
Index: src/SynTree/NamedTypeDecl.cc
===================================================================
--- src/SynTree/NamedTypeDecl.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/SynTree/NamedTypeDecl.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -29,5 +29,4 @@
 NamedTypeDecl::NamedTypeDecl( const NamedTypeDecl &other )
 	: Parent( other ), base( maybeClone( other.base ) ) {
-	cloneAll( other.parameters, parameters );
 	cloneAll( other.assertions, assertions );
 }
@@ -35,5 +34,4 @@
 NamedTypeDecl::~NamedTypeDecl() {
 	delete base;
-	deleteAll( parameters );
 	deleteAll( assertions );
 }
@@ -56,8 +54,4 @@
 		base->print( os, indent+1 );
 	} // if
-	if ( ! parameters.empty() ) {
-		os << endl << indent << "... with parameters" << endl;
-		printAll( parameters, os, indent+1 );
-	} // if
 	if ( ! assertions.empty() ) {
 		os << endl << indent << "... with assertions" << endl;
@@ -76,8 +70,4 @@
 		base->print( os, indent+1 );
 	} // if
-	if ( ! parameters.empty() ) {
-		os << endl << indent << "... with parameters" << endl;
-		printAll( parameters, os, indent+1 );
-	} // if
 }
 
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ src/Tuples/TupleAssignment.cc	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -504,7 +504,6 @@
 
 			std::vector< ast::ptr< ast::Expr > > match() override {
-				// temporary workaround for new and old ast to coexist and avoid name collision
-				static UniqueName lhsNamer( "__massassign_Ln" );
-				static UniqueName rhsNamer( "__massassign_Rn" );
+				static UniqueName lhsNamer( "__massassign_L" );
+				static UniqueName rhsNamer( "__massassign_R" );
 				// empty tuple case falls into this matcher
 				assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
@@ -535,7 +534,6 @@
 
 			std::vector< ast::ptr< ast::Expr > > match() override {
-				// temporary workaround for new and old ast to coexist and avoid name collision
-				static UniqueName lhsNamer( "__multassign_Ln" );
-				static UniqueName rhsNamer( "__multassign_Rn" );
+				static UniqueName lhsNamer( "__multassign_L" );
+				static UniqueName rhsNamer( "__multassign_R" );
 
 				if ( lhs.size() != rhs.size() ) return {};
Index: tests/errors/.expect/completeType.nast.x64.txt
===================================================================
--- tests/errors/.expect/completeType.nast.x64.txt	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ tests/errors/.expect/completeType.nast.x64.txt	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -12,5 +12,5 @@
       Application of
         Variable Expression: *?: forall
-          DT: data type
+          instance of type DT (not function type)
           function
         ... with parameters
@@ -21,5 +21,5 @@
         ... with resolved type:
           pointer to forall
-            [unbound]:data type
+            instance of type [unbound] (not function type)
             function
           ... with parameters
@@ -41,5 +41,5 @@
     void
   )
-  Environment:([unbound]) -> instance of struct A without body (no widening)
+  Environment:([unbound]DT) -> instance of struct A without body (no widening)
 
 
@@ -47,5 +47,5 @@
       Application of
         Variable Expression: *?: forall
-          DT: data type
+          instance of type DT (not function type)
           function
         ... with parameters
@@ -56,5 +56,5 @@
         ... with resolved type:
           pointer to forall
-            [unbound]:data type
+            instance of type [unbound] (not function type)
             function
           ... with parameters
@@ -76,5 +76,5 @@
     void
   )
-  Environment:([unbound]) -> instance of struct B with body (no widening)
+  Environment:([unbound]DT) -> instance of struct B with body (no widening)
 
 
@@ -113,7 +113,15 @@
 Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
             Variable Expression: baz: forall
-              T: sized data type
-              ... with assertions
-                ?=?: pointer to function
+              instance of type T (not function type)
+              with assertions
+              Variable Expression: ?=?: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+                instance of type T (not function type)
+              ... returning
+                instance of type T (not function type)
+
+              ... with resolved type:
+                pointer to function
                 ... with parameters
                   reference to instance of type T (not function type)
@@ -122,20 +130,38 @@
                   instance of type T (not function type)
 
-                ?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                ... returning nothing
-
-                ?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                  instance of type T (not function type)
-                ... returning nothing
-
-                ^?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                ... returning nothing
-
+              Variable Expression: ?{}: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+              ... returning nothing
+
+              ... with resolved type:
+                pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+              Variable Expression: ?{}: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+                instance of type T (not function type)
+              ... returning nothing
+
+              ... with resolved type:
+                pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning nothing
+
+              Variable Expression: ^?{}: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+              ... returning nothing
+
+              ... with resolved type:
+                pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
 
               function
@@ -146,7 +172,15 @@
             ... with resolved type:
               pointer to forall
-                [unbound]:sized data type
-                ... with assertions
-                  ?=?: pointer to function
+                instance of type [unbound] (not function type)
+                with assertions
+                Variable Expression: ?=?: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning
+                  instance of type T (not function type)
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
@@ -155,10 +189,23 @@
                     instance of type [unbound] (not function type)
 
-                  ?{}: pointer to function
+                Variable Expression: ?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
                   ... returning nothing
 
-                  ?{}: pointer to function
+                Variable Expression: ?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning nothing
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
@@ -166,9 +213,14 @@
                   ... returning nothing
 
-                  ^?{}: pointer to function
+                Variable Expression: ^?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
                   ... returning nothing
-
 
                 function
@@ -188,12 +240,20 @@
           void
         )
-        Environment:([unbound]) -> instance of type T (not function type) (no widening)
+        Environment:([unbound]T) -> instance of type T (not function type) (no widening)
 
       Could not satisfy assertion:
-?=?: pointer to function
+Variable Expression: ?=?: pointer to function
         ... with parameters
-          reference to instance of type [unbound] (not function type)
-          instance of type [unbound] (not function type)
+          reference to instance of type T (not function type)
+          instance of type T (not function type)
         ... returning
-          instance of type [unbound] (not function type)
-
+          instance of type T (not function type)
+
+        ... with resolved type:
+          pointer to function
+          ... with parameters
+            reference to instance of type [unbound] (not function type)
+            instance of type [unbound] (not function type)
+          ... returning
+            instance of type [unbound] (not function type)
+
Index: tests/errors/.expect/completeType.nast.x86.txt
===================================================================
--- tests/errors/.expect/completeType.nast.x86.txt	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ tests/errors/.expect/completeType.nast.x86.txt	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -12,5 +12,5 @@
       Application of
         Variable Expression: *?: forall
-          DT: data type
+          instance of type DT (not function type)
           function
         ... with parameters
@@ -21,5 +21,5 @@
         ... with resolved type:
           pointer to forall
-            [unbound]:data type
+            instance of type [unbound] (not function type)
             function
           ... with parameters
@@ -41,5 +41,5 @@
     void
   )
-  Environment:([unbound]) -> instance of struct A without body (no widening)
+  Environment:([unbound]DT) -> instance of struct A without body (no widening)
 
 
@@ -47,5 +47,5 @@
       Application of
         Variable Expression: *?: forall
-          DT: data type
+          instance of type DT (not function type)
           function
         ... with parameters
@@ -56,5 +56,5 @@
         ... with resolved type:
           pointer to forall
-            [unbound]:data type
+            instance of type [unbound] (not function type)
             function
           ... with parameters
@@ -76,5 +76,5 @@
     void
   )
-  Environment:([unbound]) -> instance of struct B with body (no widening)
+  Environment:([unbound]DT) -> instance of struct B with body (no widening)
 
 
@@ -113,7 +113,15 @@
 Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
             Variable Expression: baz: forall
-              T: sized data type
-              ... with assertions
-                ?=?: pointer to function
+              instance of type T (not function type)
+              with assertions
+              Variable Expression: ?=?: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+                instance of type T (not function type)
+              ... returning
+                instance of type T (not function type)
+
+              ... with resolved type:
+                pointer to function
                 ... with parameters
                   reference to instance of type T (not function type)
@@ -122,20 +130,38 @@
                   instance of type T (not function type)
 
-                ?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                ... returning nothing
-
-                ?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                  instance of type T (not function type)
-                ... returning nothing
-
-                ^?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                ... returning nothing
-
+              Variable Expression: ?{}: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+              ... returning nothing
+
+              ... with resolved type:
+                pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+              Variable Expression: ?{}: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+                instance of type T (not function type)
+              ... returning nothing
+
+              ... with resolved type:
+                pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning nothing
+
+              Variable Expression: ^?{}: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+              ... returning nothing
+
+              ... with resolved type:
+                pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
 
               function
@@ -146,7 +172,15 @@
             ... with resolved type:
               pointer to forall
-                [unbound]:sized data type
-                ... with assertions
-                  ?=?: pointer to function
+                instance of type [unbound] (not function type)
+                with assertions
+                Variable Expression: ?=?: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning
+                  instance of type T (not function type)
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
@@ -155,10 +189,23 @@
                     instance of type [unbound] (not function type)
 
-                  ?{}: pointer to function
+                Variable Expression: ?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
                   ... returning nothing
 
-                  ?{}: pointer to function
+                Variable Expression: ?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning nothing
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
@@ -166,9 +213,14 @@
                   ... returning nothing
 
-                  ^?{}: pointer to function
+                Variable Expression: ^?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
                   ... returning nothing
-
 
                 function
@@ -188,12 +240,20 @@
           void
         )
-        Environment:([unbound]) -> instance of type T (not function type) (no widening)
+        Environment:([unbound]T) -> instance of type T (not function type) (no widening)
 
       Could not satisfy assertion:
-?=?: pointer to function
+Variable Expression: ?=?: pointer to function
         ... with parameters
-          reference to instance of type [unbound] (not function type)
-          instance of type [unbound] (not function type)
+          reference to instance of type T (not function type)
+          instance of type T (not function type)
         ... returning
-          instance of type [unbound] (not function type)
-
+          instance of type T (not function type)
+
+        ... with resolved type:
+          pointer to function
+          ... with parameters
+            reference to instance of type [unbound] (not function type)
+            instance of type [unbound] (not function type)
+          ... returning
+            instance of type [unbound] (not function type)
+
Index: tests/heap.cfa
===================================================================
--- tests/heap.cfa	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ tests/heap.cfa	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -10,6 +10,6 @@
 // Created On       : Tue Nov  6 17:54:56 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Sep 25 15:21:52 2020
-// Update Count     : 73
+// Last Modified On : Tue Dec 15 12:11:51 2020
+// Update Count     : 79
 // 
 
@@ -27,7 +27,10 @@
 // }
 
-#define __U_DEFAULT_MMAP_START__ (512 * 1024 + 1)
-size_t default_mmap_start() __attribute__(( weak )) {
-	return __U_DEFAULT_MMAP_START__;
+size_t default_heap_expansion() {
+	return 10 * 1024 * 1024;
+} // default_heap_expansion
+
+size_t default_mmap_start() {
+	return 512 * 1024 + 1;
 } // default_mmap_start
 
Index: tests/raii/.expect/ctor-autogen-ERR1.nast.txt
===================================================================
--- tests/raii/.expect/ctor-autogen-ERR1.nast.txt	(revision b3c8496a418823a0579dda2d3179e4d6e61a1c8b)
+++ tests/raii/.expect/ctor-autogen-ERR1.nast.txt	(revision 53449a48dee3324f96932ed8c4befe2756837314)
@@ -70,5 +70,4 @@
             ... with environment:
               Types:
-              Non-types:
 
 
