Index: libcfa/src/bits/collection.hfa
===================================================================
--- libcfa/src/bits/collection.hfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/bits/collection.hfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -1,10 +1,12 @@
 #pragma once
+#include <stdio.h> // REMOVE THIS AFTER DEBUGGING
+
 
 struct Colable {
-	Colable * next;										// next node in the list
+	struct Colable * next;										// next node in the list
 	// invariant: (next != 0) <=> listed()
 };
-
-inline {
+#ifdef __cforall
+static inline {
 	// PUBLIC
 
@@ -28,14 +30,14 @@
 	}
 
-	// wrappers to make Collection have T
-	forall( dtype T ) {
-		T *& Next( T * n ) {
-			return (T *)Next( (Colable *)n );
-		}
+	// // wrappers to make Collection have T
+	// forall( dtype T ) {
+	// 	T *& Next( T * n ) {
+	// 		return (T *)Next( (Colable *)n );
+	// 	}
 
-		bool listed( T * n ) {
-			return Next( (Colable *)n ) != 0p;
-		}
-	} // distribution
+	// 	bool listed( T * n ) {
+	// 		return Next( (Colable *)n ) != 0p;
+	// 	}
+	// } // distribution
 } // distribution
 
@@ -45,5 +47,5 @@
 };
 
-inline {
+static inline {
 	// class invariant: root == 0 & empty() | *root in *this
 	void ?{}( Collection &, const Collection & ) = void; // no copy
@@ -68,5 +70,5 @@
 };
 
-inline {
+static inline {
 	void ?{}( ColIter & colIter ) with( colIter ) {
 		curr = 0p;
@@ -79,2 +81,3 @@
 	} // distribution
 } // distribution
+#endif
Index: libcfa/src/bits/containers.hfa
===================================================================
--- libcfa/src/bits/containers.hfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/bits/containers.hfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -36,5 +36,5 @@
 	#define __small_array_t(T) __small_array(T)
 #else
-	#define __small_array_t(T) struct __small_array
+	#define __small_array_t(T) __small_array
 #endif
 
Index: libcfa/src/bits/defs.hfa
===================================================================
--- libcfa/src/bits/defs.hfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/bits/defs.hfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -29,5 +29,5 @@
 #define __cfa_anonymous_object(x) inline struct x
 #else
-#define __cfa_anonymous_object(x) x __cfa_anonymous_object
+#define __cfa_anonymous_object(x) struct x __cfa_anonymous_object
 #endif
 
Index: libcfa/src/bits/queue.hfa
===================================================================
--- libcfa/src/bits/queue.hfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/bits/queue.hfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -3,5 +3,5 @@
 #include "bits/collection.hfa"
 
-forall( dtype T ) {
+forall( dtype T | { T *& Next ( T * ); bool listed ( T * ); } ) {
 	struct Queue {
 		inline Collection;								// Plan 9 inheritance
@@ -64,5 +64,5 @@
 			T & t = head( q );
 			if ( root ) {
-				root = Next( root );
+				root = Next( (T *)root );
 				if ( &head( q ) == &t ) {
 					root = last = 0p;					// only one element
@@ -142,5 +142,5 @@
 } // distribution
 
-forall( dtype T ) {
+forall( dtype T | { T *& Next ( T * ); bool listed ( T * ); } ) {
 	struct QueueIter {
 		inline ColIter;									// Plan 9 inheritance
Index: libcfa/src/bits/sequence.hfa
===================================================================
--- libcfa/src/bits/sequence.hfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/bits/sequence.hfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -2,11 +2,13 @@
 
 #include "bits/collection.hfa"
+#include "bits/defs.hfa"
 
 struct Seqable {
-	inline Colable;
-	Seqable * back;										// pointer to previous node in the list
+	__cfa_anonymous_object(Colable);
+	struct Seqable * back;										// pointer to previous node in the list
 };
 
-inline {
+#ifdef __cforall
+static inline {
 	// PUBLIC
 
@@ -26,18 +28,18 @@
 	}
 
-	// wrappers to make Collection have T
-	forall( dtype T ) {
-		T *& Back( T * n ) {
-			return (T *)Back( (Seqable *)n );
-		}
-	} // distribution
+	// // wrappers to make Collection have T
+	// forall( dtype T ) {
+	// 	T *& Back( T * n ) {
+	// 		return (T *)Back( (Seqable *)n );
+	// 	}
+	// } // distribution
 } // distribution
 
-forall( dtype T ) {
+forall( dtype T | { T *& Back ( T * ); T *& Next ( T * ); bool listed ( T * ); } ) {
 	struct Sequence {
 		inline Collection;								// Plan 9 inheritance
 	};
 
-	inline {
+	static inline {
 		// wrappers to make Collection have T
 		T & head( Sequence(T) & s ) with( s ) {
@@ -184,7 +186,7 @@
 				T * toEnd = Back( &head( s ) );
 				T * fromEnd = Back( &head( from ) );
-				Back( root ) = fromEnd;
+				Back( (T *)root ) = fromEnd;
 				Next( fromEnd ) = &head( s );
-				Back( from.root ) = toEnd;
+				Back( (T *)from.root ) = toEnd;
 				Next( toEnd ) = &head( from );
 			} // if
@@ -214,5 +216,5 @@
 } // distribution
 
-forall( dtype T ) {
+forall( dtype T | { T *& Back ( T * ); T *& Next ( T * ); bool listed ( T * ); } ) {
 	// SeqIter(T) is used to iterate over a Sequence(T) in head-to-tail order.
 	struct SeqIter {
@@ -224,5 +226,5 @@
 	};
 
-	inline {
+	static inline {
 		void ?{}( SeqIter(T) & si ) with( si ) {
 			((ColIter &)si){};
@@ -265,5 +267,5 @@
 	};
 
-	inline {
+	static inline {
 		void ?{}( SeqIterRev(T) & si ) with( si ) {	
 			((ColIter &)si){};
@@ -298,2 +300,4 @@
 	} // distribution
 } // distribution
+
+#endif
Index: libcfa/src/bits/stack.hfa
===================================================================
--- libcfa/src/bits/stack.hfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/bits/stack.hfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -3,5 +3,5 @@
 #include "bits/collection.hfa"
 
-forall( dtype T ) {
+forall( dtype T | { T *& Next ( T * ); bool listed ( T * ); } ) {
 	struct Stack {
 		inline Collection;								// Plan 9 inheritance
@@ -44,5 +44,5 @@
 			T & t = head( s );
 			if ( root ) {
-				root = ( T *)Next( root );
+				root = ( T *)Next( (T *)root );
 				if ( &head( s ) == &t ) root = 0p;		// only one element ?
 				Next( &t ) = 0p;
@@ -58,5 +58,5 @@
 
 
-forall( dtype T ) {
+forall( dtype T | { T *& Next ( T * ); bool listed ( T * ); } ) {
 	struct StackIter {
 		inline ColIter;									// Plan 9 inheritance
Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/concurrency/coroutine.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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
 //
 
@@ -88,4 +88,5 @@
 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 );
@@ -206,5 +207,5 @@
 		__cfaabi_dbg_debug_do(
 			storage = (char*)(storage) - __page_size;
-			if ( mprotect( storage, __page_size, PROT_READ | PROT_WRITE ) == -1 ) {
+			if ( mprotect( storage, __page_size, __map_prot ) == -1 ) {
 				abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) );
 			}
Index: libcfa/src/concurrency/invoke.h
===================================================================
--- libcfa/src/concurrency/invoke.h	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/concurrency/invoke.h	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -189,4 +189,10 @@
 		struct __monitor_group_t monitors;
 
+		// used to put threads on user data structures
+		struct {
+			struct $thread * next;
+			struct $thread * back;
+		} seqable;
+
 		struct {
 			struct $thread * next;
@@ -218,4 +224,16 @@
 		}
 
+		static inline $thread *& Back( $thread * this ) __attribute__((const)) {
+			return this->seqable.back;
+		}
+
+		static inline $thread *& Next( $thread * this ) __attribute__((const)) {
+			return this->seqable.next;
+		}
+
+		static inline bool listed( $thread * this ) {
+			return this->seqable.next != 0p;
+		}
+
 		static inline void ?{}(__monitor_group_t & this) {
 			(this.data){0p};
Index: libcfa/src/concurrency/kernel/startup.cfa
===================================================================
--- libcfa/src/concurrency/kernel/startup.cfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/concurrency/kernel/startup.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -117,5 +117,5 @@
 }
 
-size_t __page_size = 0;
+extern size_t __page_size;
 
 //-----------------------------------------------------------------------------
@@ -161,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 };
@@ -681,5 +679,5 @@
 	#if CFA_PROCESSOR_USE_MMAP
 		stacksize = ceiling( stacksize, __page_size ) + __page_size;
-		stack = mmap(0p, stacksize, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+		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 ) );
Index: libcfa/src/concurrency/locks.cfa
===================================================================
--- libcfa/src/concurrency/locks.cfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/concurrency/locks.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -29,4 +29,16 @@
 
 	void ^?{}( info_thread(L) & this ){ }
+
+	info_thread(L) *& Back( info_thread(L) * this ) {
+		return (info_thread(L) *)Back( (Seqable *)this );
+	}
+
+	info_thread(L) *& Next( info_thread(L) * this ) {
+		return (info_thread(L) *)Next( (Colable *)this );
+	}
+
+	bool listed( info_thread(L) * this ) {
+		return Next( (Colable *)this ) != 0p;
+	}
 }
 
@@ -58,5 +70,5 @@
 		abort("A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock.");
 	} else if ( owner != 0p && owner != active_thread() ) {
-		append( blocked_threads, active_thread() );
+		addTail( blocked_threads, *active_thread() );
 		wait_count++;
 		unlock( lock );
@@ -96,5 +108,5 @@
 
 void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
-	$thread * t = pop_head( blocked_threads );
+	$thread * t = &dropHead( blocked_threads );
 	owner = t;
 	recursion_count = ( t ? 1 : 0 );
@@ -128,5 +140,5 @@
     lock( lock __cfaabi_dbg_ctx2 );
 	if ( owner != 0p ) {
-		append( blocked_threads, t );
+		addTail( blocked_threads, *t );
 		wait_count++;
 		unlock( lock );
@@ -257,5 +269,4 @@
 		size_t recursion_count = 0;
 		if (i->lock) {
-			i->t->link.next = 1p;
 			recursion_count = get_recursion_count(*i->lock);
 			remove_( *i->lock );
Index: libcfa/src/concurrency/locks.hfa
===================================================================
--- libcfa/src/concurrency/locks.hfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/concurrency/locks.hfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -43,4 +43,8 @@
 	void ?{}( info_thread(L) & this, $thread * t, uintptr_t info );
 	void ^?{}( info_thread(L) & this );
+
+	info_thread(L) *& Back( info_thread(L) * this );
+	info_thread(L) *& Next( info_thread(L) * this );
+	bool listed( info_thread(L) * this );
 }
 
@@ -64,5 +68,5 @@
 
 	// List of blocked threads
-	__queue_t( $thread ) blocked_threads;
+	Sequence( $thread ) blocked_threads;
 
 	// Count of current blocked threads
Index: libcfa/src/concurrency/thread.cfa
===================================================================
--- libcfa/src/concurrency/thread.cfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/concurrency/thread.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -43,4 +43,7 @@
 		canary = 0x0D15EA5E0D15EA5Ep;
 	#endif
+
+	seqable.next = 0p;
+	seqable.back = 0p;
 
 	node.next = 0p;
Index: libcfa/src/heap.cfa
===================================================================
--- libcfa/src/heap.cfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ libcfa/src/heap.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -10,9 +10,10 @@
 // Created On       : Tue Dec 19 21:58:35 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Dec 13 22:04:10 2020
-// Update Count     : 984
+// 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__
 
@@ -482,4 +484,5 @@
 #endif // __CFA_DEBUG__
 
+
 #define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes."
 
@@ -490,15 +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, pageSize );
+		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
-		} // if
-		if ( mprotect( (char *)heapEnd + heapRemaining, increase, PROT_READ | PROT_WRITE | PROT_EXEC ) ) {
-			enum { BufferSize = 128 };
-			char helpText[BufferSize];
-			// Do not call strerror( errno ) as it may call malloc.
-			int len = snprintf( helpText, BufferSize, "internal error, extend(), mprotect failure, heapEnd:%p size:%zd, errno:%d.", heapEnd, increase, errno );
-			__cfaabi_bits_write( STDERR_FILENO, helpText, len );
+			__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__
@@ -508,6 +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, increase );
+		memset( (char *)heapEnd + heapRemaining, '\xde', increase );
+		//Memset( (char *)heapEnd + heapRemaining, increase );
 		#endif // __CFA_DEBUG__
 		rem = heapRemaining + increase - size;
@@ -568,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 );
@@ -575,5 +578,5 @@
 		#endif // __STATISTICS__
 
-		block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE | PROT_EXEC, 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
@@ -583,6 +586,6 @@
 		#ifdef __CFA_DEBUG__
 		// Set new memory to garbage so subsequent uninitialized usages might fail.
-		//memset( block, '\377', tsize );
-		Memset( block, tsize );
+		memset( block, '\xde', tsize );
+		//Memset( block, tsize );
 		#endif // __CFA_DEBUG__
 		block->header.kind.real.blockSize = tsize;		// storage size for munmap
@@ -624,15 +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, 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__
 
@@ -703,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
@@ -723,5 +725,5 @@
 
 	char * end = (char *)sbrk( 0 );
-	heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, pageSize ) - 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
 
@@ -741,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
@@ -1028,4 +1029,5 @@
 	} // cmemalign
 
+
 	// Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
     // of alignment. This requirement is universally ignored.
@@ -1045,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
 
@@ -1054,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
 
@@ -1193,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;
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Convert.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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);
@@ -602,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) );
 		}
 
@@ -1212,5 +1212,25 @@
 		// 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 );
 	}
@@ -1299,5 +1319,5 @@
 			ty = new TypeInstType{
 				cv( node ),
-				node->name,
+				node->typeString(),
 				get<TypeDecl>().accept1( node->base ),
 				get<Attribute>().acceptL( node->attributes )
@@ -1306,5 +1326,5 @@
 			ty = new TypeInstType{
 				cv( node ),
-				node->name,
+				node->typeString(),
 				node->kind == ast::TypeDecl::Ftype,
 				get<Attribute>().acceptL( node->attributes )
@@ -1431,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:
@@ -1565,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{
@@ -1584,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);
@@ -2066,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();
 
@@ -2077,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;
+		*/
 	}
 
@@ -2610,5 +2643,14 @@
 			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 );
 	}
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Decl.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Decl.hpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -127,8 +127,11 @@
 	std::vector<ptr<DeclWithType>> params;
 	std::vector<ptr<DeclWithType>> returns;
+	std::vector<ptr<TypeDecl>> type_params;
+	std::vector<ptr<DeclWithType>> assertions;
 	// declared type, derived from parameter declarations
 	ptr<FunctionType> type;
 	ptr<CompoundStmt> stmts;
 	std::vector< ptr<Expr> > withExprs;
+
 
 	FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Expr.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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: c/AST/ForallSubstitutionTable.cpp
===================================================================
--- src/AST/ForallSubstitutionTable.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ 	(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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ 	(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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ 	(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
-	FunctionType::ForallList operator() ( const FunctionType::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/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Pass.hpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Pass.impl.hpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 );
@@ -1758,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  );
@@ -1981,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 };
@@ -1994,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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Pass.proto.hpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -413,13 +413,4 @@
 		static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
 
-		// 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; }
-
 		// Replaces a TypeInstType's base TypeDecl according to the table
 		template<typename core_t>
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Print.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -155,4 +155,13 @@
 	}
 
+	void print( const ast::FunctionType::AssertionList & assts ) {
+		if (assts.empty()) return;
+		os << "with assertions" << endl;
+		++indent;
+		printAll(assts);
+		os << indent;
+		--indent;
+	}
+
 	void print( const std::vector<ptr<Attribute>> & attrs ) {
 		if ( attrs.empty() ) return;
@@ -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 << ": ";
 		}
 
@@ -261,4 +269,5 @@
 	void preprint( const ast::FunctionType * node ) {
 		print( node->forall );
+		print( node->assertions );
 		print( node->qualifiers );
 	}
@@ -1375,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)";
@@ -1502,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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/SymbolTable.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Type.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 FunctionType::initWithSub(
-	const FunctionType & o, Pass< ForallSubstitutor > & sub
-) {
-	forall = sub.core( o.forall );
-}
-
 // --- FunctionType
-
-
-FunctionType::FunctionType( const FunctionType & o )
-: Type( 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 ) {
@@ -199,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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/Type.hpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -36,6 +36,4 @@
 
 template< typename T > class Pass;
-
-struct ForallSubstitutor;
 
 class Type : public Node {
@@ -272,10 +270,9 @@
 /// Type of a function `[R1, R2](*)(P1, P2, P3)`
 class FunctionType final : public Type {
-	protected:
-	/// initializes forall with substitutor
-	void initWithSub( const FunctionType & o, Pass< ForallSubstitutor > & sub );
-public:
-	using ForallList = std::vector<ptr<TypeDecl>>;
+public:
+	using ForallList = std::vector<ptr<TypeInstType>>;
+	using AssertionList = std::vector<ptr<VariableExpr>>;
 	ForallList forall;
+	AssertionList assertions;
 
 	std::vector<ptr<Type>> returns;
@@ -292,5 +289,5 @@
 	: Type(q), returns(), params(), isVarArgs(va) {}
 
-	FunctionType( const FunctionType & o );
+	FunctionType( const FunctionType & o ) = default;
 
 	/// true if either the parameters or return values contain a tttype
@@ -397,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(
@@ -409,4 +427,7 @@
 	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
 	void set_base( const TypeDecl * );
@@ -418,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 }; }
@@ -510,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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/TypeEnvironment.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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;
@@ -106,5 +109,5 @@
 
 void TypeEnvironment::add( const FunctionType::ForallList & tyDecls ) {
-	for ( const TypeDecl * tyDecl : 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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/TypeEnvironment.hpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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,5 +131,5 @@
 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
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/TypeSubstitution.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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,24 +152,15 @@
 }
 
-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 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 );
@@ -184,5 +171,5 @@
 			if ( ! type->params.empty() ) {
 				for ( const TypeDecl * tyvar : decl->params ) {
-					boundVars.insert( tyvar->name );
+					boundVars.insert( *tyvar );
 				} // for
 			} // if
@@ -198,4 +185,5 @@
 	handleAggregateType( aggregateUseType );
 }
+*/
 
 } // namespace ast
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/TypeSubstitution.hpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/AST/module.mk	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/GenPoly/GenPoly.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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}));
 	}
 
Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/AdjustExprType.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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;
@@ -223,9 +221,9 @@
 		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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/CastCost.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/CommonType.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/ConversionCost.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/FindOpenVars.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/PolyCost.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/PtrsAssignable.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/PtrsCastable.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/RenameVars.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 @@
 		}
 
-		const ast::FunctionType * openLevel( const ast::FunctionType * 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.
-			auto mutType = ast::mutate( type );
-			assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
-			for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
-				assertf(dynamic_cast<ast::FunctionType *>(mutType), "renaming vars in non-function type");
-				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;
+			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,10 +151,9 @@
 	};
 
-	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 );
 		}
 
@@ -163,4 +171,5 @@
 
 		const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
+			if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type
 			return renaming.rename( type );
 		}
@@ -177,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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/RenameVars.h	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/Resolver.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -986,5 +986,4 @@
 		};
 	} // anonymous namespace
-
 	/// Check if this expression is or includes a deleted expression
 	const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
@@ -1375,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));
 			}
 
@@ -1407,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);
@@ -1418,4 +1421,5 @@
 			symtab.leaveScope();
 
+			mutDecl->type = renamedType;
 			mutDecl->mangleName = Mangle::mangle(mutDecl);
 			mutDecl->isTypeFixed = true;
@@ -1534,6 +1538,5 @@
 	const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) {
 		if ( type->dimension ) {
-			#warning should use new equivalent to Validate::SizeType rather than sizeType here
-			ast::ptr< ast::Type > sizeType = new ast::BasicType{ ast::BasicType::LongUnsignedInt };
+			ast::ptr< ast::Type > sizeType = ast::sizeType;
 			ast::mutate_field(
 				type, &PtrType::dimension,
Index: src/ResolvExpr/SatisfyAssertions.cpp
===================================================================
--- src/ResolvExpr/SatisfyAssertions.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/SatisfyAssertions.cpp	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 ) {
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/ResolvExpr/Unify.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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() ) {
@@ -900,9 +900,7 @@
 			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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/SymTab/Mangler.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -671,5 +671,5 @@
 					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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/SymTab/Validate.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -1463,4 +1463,6 @@
 	}
 
+	/*
+
 	/// Associates forward declarations of aggregates with their definitions
 	class LinkReferenceToTypes_new final
@@ -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/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ src/Tuples/TupleAssignment.cc	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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/.expect/KRfunctions.nast.x86.txt
===================================================================
--- tests/.expect/KRfunctions.nast.x86.txt	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/.expect/KRfunctions.nast.x86.txt	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -86,12 +86,12 @@
     __attribute__ ((unused)) signed int (*_X11_retval_f11PA0i_1)[];
 }
-signed int (*_X3f12FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned long int )10)]{
-    __attribute__ ((unused)) signed int (*_X11_retval_f12PA0A0i_1)[][((unsigned long int )10)];
+signed int (*_X3f12FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned int )10)]{
+    __attribute__ ((unused)) signed int (*_X11_retval_f12PA0A0i_1)[][((unsigned int )10)];
 }
-signed int (*_X3f13FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned long int )10)]{
-    __attribute__ ((unused)) signed int (*_X11_retval_f13PA0A0i_1)[][((unsigned long int )10)];
+signed int (*_X3f13FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned int )10)]{
+    __attribute__ ((unused)) signed int (*_X11_retval_f13PA0A0i_1)[][((unsigned int )10)];
 }
-signed int (*_X3f14FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned long int )10)]{
-    __attribute__ ((unused)) signed int (*_X11_retval_f14PA0A0i_1)[][((unsigned long int )10)];
+signed int (*_X3f14FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned int )10)]{
+    __attribute__ ((unused)) signed int (*_X11_retval_f14PA0A0i_1)[][((unsigned int )10)];
 }
 signed int _X3f15Fi_iii__1(signed int _X1ai_1, signed int _X1bi_1, signed int _X1ci_1){
Index: tests/.expect/attributes.nast.x86.txt
===================================================================
--- tests/.expect/attributes.nast.x86.txt	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/.expect/attributes.nast.x86.txt	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -623,6 +623,6 @@
 __attribute__ ((used,used,used,used)) const signed int *_X3vd3PKi_1;
 __attribute__ ((used,used,unused,used,unused)) const signed int *_X3vd4PKi_1;
-__attribute__ ((used,used,used)) const signed int _X3vd5A0Ki_1[((unsigned long int )5)];
-__attribute__ ((used,used,unused,used)) const signed int _X3vd6A0Ki_1[((unsigned long int )5)];
+__attribute__ ((used,used,used)) const signed int _X3vd5A0Ki_1[((unsigned int )5)];
+__attribute__ ((used,used,unused,used)) const signed int _X3vd6A0Ki_1[((unsigned int )5)];
 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
@@ -647,6 +647,6 @@
     __attribute__ ((unused,unused,used)) signed int _X2t1i_2;
     __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t2PPi_2;
-    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)];
-    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)];
+    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)];
+    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)];
     __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
     __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
@@ -671,5 +671,5 @@
 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
-signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned long int )5)]));
+signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned int )5)]));
 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
@@ -679,6 +679,6 @@
     __attribute__ ((used,unused)) signed int _X3ad1i_2;
     __attribute__ ((unused,unused,unused)) signed int *_X3ad2Pi_2;
-    __attribute__ ((unused,unused,unused)) signed int _X3ad3A0i_2[((unsigned long int )5)];
-    __attribute__ ((unused,unused,unused,unused,unused)) signed int (*_X3ad4PA0i_2)[((unsigned long int )10)];
+    __attribute__ ((unused,unused,unused)) signed int _X3ad3A0i_2[((unsigned int )5)];
+    __attribute__ ((unused,unused,unused,unused,unused)) signed int (*_X3ad4PA0i_2)[((unsigned int )10)];
     __attribute__ ((unused,unused,unused,unused,used)) signed int _X3ad5i_2;
     __attribute__ ((unused,unused,unused,unused,unused)) signed int _X3ad6Fi___2();
Index: tests/.expect/functions.nast.x86.txt
===================================================================
--- tests/.expect/functions.nast.x86.txt	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/.expect/functions.nast.x86.txt	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -46,9 +46,9 @@
     __attribute__ ((unused)) signed int (*_X11_retval_f10PA0i_1)[];
 }
-signed int (*_X3f11FPA0A0i___1())[][((unsigned long int )3)]{
-    __attribute__ ((unused)) signed int (*_X11_retval_f11PA0A0i_1)[][((unsigned long int )3)];
-}
-signed int (*_X3f12FPA0A0i___1())[][((unsigned long int )3)]{
-    __attribute__ ((unused)) signed int (*_X11_retval_f12PA0A0i_1)[][((unsigned long int )3)];
+signed int (*_X3f11FPA0A0i___1())[][((unsigned int )3)]{
+    __attribute__ ((unused)) signed int (*_X11_retval_f11PA0A0i_1)[][((unsigned int )3)];
+}
+signed int (*_X3f12FPA0A0i___1())[][((unsigned int )3)]{
+    __attribute__ ((unused)) signed int (*_X11_retval_f12PA0A0i_1)[][((unsigned int )3)];
 }
 signed int _X4fII1Fi_i__1(signed int _X1ii_1){
@@ -250,6 +250,6 @@
 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object20)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object21)(signed int __param_0)){
     __attribute__ ((unused)) signed int _X9_retval_fi_1;
-    signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)];
-    signed int (*(*_X1pPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)];
+    signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned int )10)])[][((unsigned int )3)];
+    signed int (*(*_X1pPA0A0PA0A0i_2)[][((unsigned int )10)])[][((unsigned int )3)];
     signed int (*(*_X1pPA0Fi_i__2)[])(signed int __param_0);
 }
Index: tests/errors/.expect/completeType.nast.x64.txt
===================================================================
--- tests/errors/.expect/completeType.nast.x64.txt	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/errors/.expect/completeType.nast.x64.txt	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/errors/.expect/completeType.nast.x86.txt	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/heap.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -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/multi_list.cfa
===================================================================
--- tests/multi_list.cfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/multi_list.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -19,4 +19,16 @@
 }
 
+TaskDL *& Back( TaskDL * n ) {
+	return (TaskDL *)Back( (Seqable *)n );
+}
+
+TaskDL *& Next( TaskDL * n ) {
+	return (TaskDL *)Next( (Colable *)n );
+}
+
+bool listed( TaskDL * n ) {
+	return Next( (Colable *)n ) != 0p;
+}
+
 struct TaskSL {
 	inline Colable;
@@ -29,4 +41,12 @@
 Task & task( TaskSL & this ) with( this ) {				// getter routine for containing node
 	return node;
+}
+
+TaskSL *& Next( TaskSL * n ) {
+	return (TaskSL *)Next( (Colable *)n );
+}
+
+bool listed( TaskSL * n ) {
+	return Next( (Colable *)n ) != 0p;
 }
 
Index: tests/queue.cfa
===================================================================
--- tests/queue.cfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/queue.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -13,4 +13,11 @@
 	void ?{}( Fred & fred, int p ) with( fred ) {
 		i = p;
+	}
+	Fred *& Next( Fred * n ) {
+		return (Fred *)Next( (Colable *)n );
+	}
+
+	bool listed( Fred * n ) {
+		return Next( (Colable *)n ) != 0p;
 	}
 
@@ -68,4 +75,12 @@
 	}
 
+	Mary *& Next( Mary * n ) {
+		return (Mary *)Next( (Colable *)n );
+	}
+
+	bool listed( Mary * n ) {
+		return Next( (Colable *)n ) != 0p;
+	}
+
 	Queue(Mary) mary;
 	QueueIter(Mary) maryIter = { mary };
Index: tests/raii/.expect/ctor-autogen-ERR1.nast.txt
===================================================================
--- tests/raii/.expect/ctor-autogen-ERR1.nast.txt	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/raii/.expect/ctor-autogen-ERR1.nast.txt	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -70,5 +70,4 @@
             ... with environment:
               Types:
-              Non-types:
 
 
Index: tests/sequence.cfa
===================================================================
--- tests/sequence.cfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/sequence.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -13,4 +13,16 @@
 	void ?{}( Fred & fred, int p ) with( fred ) {
 		i = p;
+	}
+
+	Fred *& Back( Fred * n ) {
+		return (Fred *)Back( (Seqable *)n );
+	}
+
+	Fred *& Next( Fred * n ) {
+		return (Fred *)Next( (Colable *)n );
+	}
+
+	bool listed( Fred * n ) {
+		return Next( (Colable *)n ) != 0p;
 	}
 
@@ -76,4 +88,16 @@
 	}
 
+	Mary *& Back( Mary * n ) {
+		return (Mary *)Back( (Seqable *)n );
+	}
+
+	Mary *& Next( Mary * n ) {
+		return (Mary *)Next( (Colable *)n );
+	}
+
+	bool listed( Mary * n ) {
+		return Next( (Colable *)n ) != 0p;
+	}
+
 	Sequence(Mary) mary;
 	Sequence(Mary) baz;
Index: tests/stack.cfa
===================================================================
--- tests/stack.cfa	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
+++ tests/stack.cfa	(revision 7a70fb209bce29c380785c7ae281c74ad784cca6)
@@ -13,4 +13,11 @@
 	void ?{}( Fred & fred, int p ) with( fred ) {
 		i = p;
+	}
+	Fred *& Next( Fred * n ) {
+		return (Fred *)Next( (Colable *)n );
+	}
+
+	bool listed( Fred * n ) {
+		return Next( (Colable *)n ) != 0p;
 	}
 
@@ -68,4 +75,12 @@
 	}
 
+	Mary *& Next( Mary * n ) {
+		return (Mary *)Next( (Colable *)n );
+	}
+
+	bool listed( Mary * n ) {
+		return Next( (Colable *)n ) != 0p;
+	}
+
 	Stack(Mary) mary;
 	StackIter(Mary) maryIter = { mary };
