Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 0292aa47c03401bae026232cc6e6461d5ae6b094)
+++ src/AST/Print.cpp	(revision a12cd59421616b42465e9fda9a08cafce3177ba6)
@@ -205,5 +205,8 @@
 
 	void preprint( const ast::NamedTypeDecl * node ) {
-		if ( ! node->name.empty() ) os << node->name << ": ";
+		if ( ! node->name.empty() ) {
+			if( deterministic_output && isUnboundType(node->name) ) os << "[unbound]:";
+			else os << node->name << ": ";
+		}
 
 		if ( ! short_mode && node->linkage != Linkage::Cforall ) {
@@ -240,11 +243,9 @@
 
 		if ( node->result ) {
-			if (!deterministic_output) {
-				os << endl << indent << "... with resolved type:" << endl;
-				++indent;
-				os << indent;
-				node->result->accept( *this );
-				--indent;
-			}
+			os << endl << indent << "... with resolved type:" << endl;
+			++indent;
+			os << indent;
+			node->result->accept( *this );
+			--indent;
 		}
 
@@ -1382,5 +1383,6 @@
 	virtual const ast::Type * visit( const ast::TypeInstType * node ) override final {
 		preprint( node );
-		os << "instance of type " << node->name
+		const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->name;
+		os << "instance of type " << _name
 		   << " (" << (node->kind == ast::TypeDecl::Ftype ? "" : "not ") << "function type)";
 		print( node->params );
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision 0292aa47c03401bae026232cc6e6461d5ae6b094)
+++ src/AST/Type.cpp	(revision a12cd59421616b42465e9fda9a08cafce3177ba6)
@@ -133,5 +133,5 @@
 
 BaseInstType::BaseInstType( const BaseInstType & o )
-: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ), 
+: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ),
   hoistType( o.hoistType ) {
 	Pass< ForallSubstitutor > sub;
@@ -222,7 +222,16 @@
 		// 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(typeInst->name.begin(), typeInst->name.end(), '_') >= 3) {
-			return true;
-		}
+		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 false;
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision 0292aa47c03401bae026232cc6e6461d5ae6b094)
+++ src/AST/Type.hpp	(revision a12cd59421616b42465e9fda9a08cafce3177ba6)
@@ -536,4 +536,5 @@
 
 bool isUnboundType(const Type * type);
+bool isUnboundType(const std::string & tname);
 
 }
Index: src/AST/TypeEnvironment.cpp
===================================================================
--- src/AST/TypeEnvironment.cpp	(revision 0292aa47c03401bae026232cc6e6461d5ae6b094)
+++ src/AST/TypeEnvironment.cpp	(revision a12cd59421616b42465e9fda9a08cafce3177ba6)
@@ -34,4 +34,5 @@
 #include "ResolvExpr/Unify.h"      // for unifyInexact
 #include "Tuples/Tuples.h"         // for isTtype
+#include "CompilationState.h"
 
 using ResolvExpr::WidenMode;
@@ -56,6 +57,12 @@
 
 void print( std::ostream & out, const EqvClass & clz, Indenter indent ) {
-	out << "( ";
-	std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) );
+	out << "(";
+	bool first = true;
+	for(const auto & var : clz.vars) {
+		if(first) first = false;
+		else out << " ";
+		if( deterministic_output && isUnboundType(var) ) out << "[unbound]";
+		else out << var;
+	}
 	out << ")";
 
