Index: src/CodeTools/DeclStats.cc
===================================================================
--- src/CodeTools/DeclStats.cc	(revision ebf0820a4adf773ed9e9bb8bf861eff3c42cc3b0)
+++ src/CodeTools/DeclStats.cc	(revision 326cd2b2de09952dae86dcf87761062515a32068)
@@ -61,10 +61,14 @@
 
 		struct ArgPackStats {
-			VectorMap<unsigned> n;                 ///< Count of decls with each number of elements
-			VectorMap<unsigned> n_basic;           ///< Count of decls with each number of basic type elements
-			VectorMap<unsigned> n_poly;            ///< Count of decls with each number of polymorphic elements
-			std::map<unsigned, unsigned> p_basic;  ///< Count of decls with each percentage of basic type elements
-			std::map<unsigned, unsigned> p_poly;   ///< Count of decls with each percentage of polymorphic elements
-			VectorMap<unsigned> n_types;           ///< Count of decls with each number of distinct types in the pack
+			VectorMap<unsigned> n;                   ///< Count of decls with each number of elements
+			VectorMap<unsigned> n_basic;             ///< Count of decls with each number of basic type elements
+			VectorMap<unsigned> n_generic;           ///< Count of decls with each number of generic type elements
+			VectorMap<unsigned> n_poly;              ///< Count of decls with each number of polymorphic elements
+			VectorMap<unsigned> n_compound;          ///< Count of decls with each number of non-generic compound types
+			std::map<unsigned, unsigned> p_basic;    ///< Count of decls with each percentage of basic type elements
+			std::map<unsigned, unsigned> p_generic;  ///< Count of decls with each percentage of generic type elements
+			std::map<unsigned, unsigned> p_poly;     ///< Count of decls with each percentage of polymorphic elements
+			std::map<unsigned, unsigned> p_compound; ///< Count of decls with each percentage of non-generic compound type elements
+			VectorMap<unsigned> n_types;             ///< Count of decls with each number of distinct types in the pack
 			/// Count of decls with each percentage of new types in lists.
 			/// Types used in the parameter list that recur in the return list are not considered to be new.
@@ -74,7 +78,11 @@
 				sum(n, o.n);
 				sum(n_basic, o.n_basic);
+				sum(n_generic, o.n_generic);
 				sum(n_poly, o.n_poly);
+				sum(n_compound, o.n_compound);
 				sum(p_basic, o.p_basic);
+				sum(p_generic, o.p_generic);
 				sum(p_poly, o.p_poly);
+				sum(p_compound, o.p_compound);
 				sum(n_types, o.n_types);
 				sum(p_new, o.p_new);
@@ -88,12 +96,20 @@
 			/// Count of declarations with each number of assertion parameters
 			VectorMap<unsigned> n_type_params;
+			/// Count of generic types with each number of type parameters
+			VectorMap<unsigned> n_generic_params;
+			/// Count of maximum nesting depth of types
+			VectorMap<unsigned> n_generic_nesting;
 			/// Count of declarations with each name
 			std::unordered_map<std::string, unsigned> by_name;
 			/// Count of uses of each basic type
 			std::unordered_map<std::string, unsigned> basic_type_names;
-			/// Count of uses of each non-basic type
+			/// Count of uses of each generic type name (includes "*", "[]", "(*)", "[,]")
+			std::unordered_map<std::string, unsigned> generic_type_names;
+			/// Count of uses of each non-generic aggregate type
 			std::unordered_map<std::string, unsigned> compound_type_names;
 			/// Count of decls using each basic type
 			std::unordered_map<std::string, unsigned> basic_type_decls;
+			/// Count of decls using each generic type (includes "*", "[]", "(*)", "[,]")
+			std::unordered_map<std::string, unsigned> generic_type_decls;
 			/// Count of decls using each compound type
 			std::unordered_map<std::string, unsigned> compound_type_decls;
@@ -110,5 +126,8 @@
 			ArgPackStats assn_returns;
 
-			Stats() : n_decls(0), n_type_params(), by_name(), basic_type_names(), compound_type_names(), basic_type_decls(), compound_type_decls(), params(), returns(), n_assns(), assn_params(), assn_returns() {}
+			Stats() : n_decls(0), n_type_params(), n_generic_params(), n_generic_nesting(), 
+				by_name(), basic_type_names(), generic_type_names(), compound_type_names(), 
+				basic_type_decls(), generic_type_decls(), compound_type_decls(), params(), 
+				returns(), n_assns(), assn_params(), assn_returns() {}
 
 		public:
@@ -116,8 +135,12 @@
 				sum( n_decls, o.n_decls );
 				sum( n_type_params, o.n_type_params );
+				sum( n_generic_params, o.n_generic_params );
+				sum( n_generic_nesting, o.n_generic_nesting );
 				sum( by_name, o.by_name );
 				sum( basic_type_names, o.basic_type_names );
+				sum( generic_type_names, o.generic_type_names );
 				sum( compound_type_names, o.compound_type_names );
 				sum( basic_type_decls, o.basic_type_decls );
+				sum( generic_type_decls, o.generic_type_decls );
 				sum( compound_type_decls, o.compound_type_decls );
 				sum( params, o.params );
@@ -131,5 +154,10 @@
 		};
 
-		Stats for_linkage[LinkageSpec::NoOfSpecs];   ///< Stores separate stats per linkage
+		/// number of counting bins for linkages
+		static const unsigned n_named_specs = 8;
+		/// map from total number of specs to bins
+		static const unsigned ind_for_linkage[16];
+
+		Stats for_linkage[n_named_specs];            ///< Stores separate stats per linkage
 		std::unordered_set<std::string> seen_names;  ///< Stores manglenames already seen to avoid double-counting
 		Stats total;
@@ -137,11 +165,149 @@
 		std::map<std::pair<unsigned, unsigned>, unsigned> exprs_by_fanout_at_depth;
 
+		void countType( const std::string& name, unsigned& n, std::unordered_map<std::string, 
+				unsigned>& names, std::unordered_map<std::string, unsigned>& decls, 
+				std::unordered_set<std::string>& elSeen ) {
+			++n;
+			++names[ name ];
+			if ( elSeen.insert( name ).second ) { ++decls[ name ]; }
+		}
+
+		void update_max( unsigned& max, unsigned crnt ) {
+			if ( crnt > max ) max = crnt;
+		}
+
+		void analyzeSubtype( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen, 
+				unsigned& n_poly, bool& seen_poly, unsigned& max_depth, unsigned depth ) {
+			unsigned x;
+			analyzeType( ty, stats, elSeen, x, x, n_poly, x, seen_poly, max_depth, depth + 1 );
+		}
+
+		void analyzeSubtypes( std::list<DeclarationWithType*>& tys, Stats& stats, 
+				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly, 
+				unsigned& max_depth, unsigned depth, unsigned& n_subs ) {
+			for ( DeclarationWithType* dwt : tys ) {
+				Type* ty = dwt->get_type();
+				n_subs += (unsigned)( dynamic_cast<VoidType*>(ty) != nullptr );
+				analyzeSubtype( ty, stats, elSeen, n_poly, seen_poly, max_depth, depth );
+			}
+		}
+
+		void analyzeSubtypes( std::list<Expression*>& tys, Stats& stats, 
+				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly, 
+				unsigned& max_depth, unsigned depth ) {
+			for ( Expression* expr : tys ) {
+				TypeExpr* texpr = dynamic_cast<TypeExpr*>(expr);
+				if ( ! texpr ) continue;
+				Type* ty = texpr->get_type();
+				analyzeSubtype( ty, stats, elSeen, n_poly, seen_poly, max_depth, depth );
+			}
+		}
+
+		void analyzeSubtypes( std::list<Type*>& tys, Stats& stats, 
+				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly, 
+				unsigned& max_depth, unsigned depth ) {
+			for ( Type* ty : tys ) {
+				analyzeSubtype( ty, stats, elSeen, n_poly, seen_poly, max_depth, depth );
+			}
+		}
+
+		void analyzeType( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen, 
+				unsigned& n_basic, unsigned& n_generic, unsigned& n_poly, unsigned& n_agg,  
+				bool& seen_poly, unsigned& max_depth, unsigned depth = 0 ) {
+			if ( BasicType* bt = dynamic_cast<BasicType*>(ty) ) {
+				std::string name = BasicType::typeNames[ bt->get_kind() ];
+				countType( name, n_basic, stats.basic_type_names, stats.basic_type_decls, elSeen );
+				update_max( max_depth, depth );
+			} else if ( PointerType* pt = dynamic_cast<PointerType*>(ty) ) {
+				std::string name = "*";
+				countType( 
+					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
+				analyzeSubtype( 
+					pt->get_base(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
+				++stats.n_generic_params.at( 1 );
+			} else if ( ArrayType* at = dynamic_cast<ArrayType*>(ty) ) {
+				std::string name = "[]";
+				countType( 
+					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
+				analyzeSubtype( 
+					at->get_base(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
+				++stats.n_generic_params.at( 1 );
+			} else if ( ReferenceType* rt = dynamic_cast<ReferenceType*>(ty) ) {
+				std::string name = "&";
+				countType( 
+					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
+				analyzeSubtype( 
+					rt->get_base(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
+				++stats.n_generic_params.at( 1 );
+			} else if ( FunctionType* ft = dynamic_cast<FunctionType*>(ty) ) {
+				std::string name = "(*)";
+				countType( 
+					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
+				unsigned n_subs = 0;
+				analyzeSubtypes( 
+					ft->get_returnVals(), stats, elSeen, n_poly, seen_poly, max_depth, depth, 
+					n_subs );
+				analyzeSubtypes( 
+					ft->get_parameters(), stats, elSeen, n_poly, seen_poly, max_depth, depth, 
+					n_subs );
+				++stats.n_generic_params.at( n_subs );
+			} else if ( TypeInstType* vt = dynamic_cast<TypeInstType*>(ty) ) {
+				if ( ! seen_poly ) {
+					++n_poly;
+					seen_poly = true;
+				}
+				countType( 
+					vt->get_name(), n_agg, stats.compound_type_names, stats.compound_type_decls, 
+					elSeen );
+				update_max( max_depth, depth );
+			} else if ( ReferenceToType* st = dynamic_cast<ReferenceToType*>(ty) ) {
+				std::list<Expression*>& params = st->get_parameters();
+				if ( params.empty() ) {
+					countType( 
+						st->get_name(), n_agg, stats.compound_type_names, 
+						stats.compound_type_decls, elSeen );
+					update_max( max_depth, depth );
+				} else {
+					countType( 
+						st->get_name(), n_generic, stats.generic_type_names, 
+						stats.generic_type_decls, elSeen);
+					analyzeSubtypes( params, stats, elSeen, n_poly, seen_poly, max_depth, depth );
+					++stats.n_generic_params.at( params.size() );
+				}
+			} else if ( TupleType* tt = dynamic_cast<TupleType*>(ty) ) {
+				std::string name = "[,]";
+				countType( 
+					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
+				analyzeSubtypes( 
+					tt->get_types(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
+				++stats.n_generic_params.at( tt->size() );
+			} else if ( dynamic_cast<VarArgsType*>(ty) ) {
+				std::string name = "...";
+				countType( 
+					name, n_agg, stats.compound_type_names, stats.compound_type_decls, elSeen );
+				update_max( max_depth, depth );
+			} else if ( dynamic_cast<ZeroType*>(ty) ) {
+				std::string name = "0";
+				countType( name, n_basic, stats.basic_type_names, stats.basic_type_decls, elSeen );
+				update_max( max_depth, depth );
+			} else if ( dynamic_cast<OneType*>(ty) ) {
+				std::string name = "1";
+				countType( name, n_basic, stats.basic_type_names, stats.basic_type_decls, elSeen );
+				update_max( max_depth, depth );
+			}
+		}
+
 		/// Update arg pack stats based on a declaration list
-		void analyze( Stats& stats, std::unordered_set<std::string>& seen, ArgPackStats& pstats, std::list<DeclarationWithType*>& decls ) {
+		void analyze( Stats& stats, std::unordered_set<std::string>& seen, 
+				std::unordered_set<std::string>& elSeen, ArgPackStats& pstats, 
+				std::list<DeclarationWithType*>& decls ) {
 			std::unordered_set<std::string> types;
-			unsigned n = 0;        ///< number of args/returns
-			unsigned n_basic = 0;  ///< number of basic types
-			unsigned n_poly = 0;   ///< number of polymorphic types
-			unsigned n_new = 0;    ///< number of new types
+			unsigned n = 0;                 ///< number of args/returns
+			unsigned n_basic = 0;           ///< number of basic types
+			unsigned n_generic = 0;         ///< number of generic types (includes "*", "&", "[]", "(*)", "[,]")
+			unsigned n_poly = 0;            ///< number of polymorphic types
+			unsigned n_agg = 0;             ///< number of non-generic aggregate types
+			unsigned n_new = 0;             ///< number of new types
+			
 			for ( auto decl : decls ) {
 				Type* dt = decl->get_type();
@@ -152,29 +318,24 @@
 				dt->print( ss );
 				types.insert( ss.str() );
-				bool this_new = seen.insert( ss.str() ).second;
-				if ( this_new ) { ++n_new; }
-
-				if ( dynamic_cast<BasicType*>( dt ) ) {
-					++n_basic;
-					++stats.basic_type_names[ ss.str() ];
-					if ( this_new ) {
-						++stats.basic_type_decls[ ss.str() ];
-					}
-				} else if ( GenPoly::hasPolyBase( dt ) ) {
-					++n_poly;
-				} else {
-					++stats.compound_type_names[ ss.str() ];
-					if ( this_new ) {
-						++stats.compound_type_decls[ ss.str() ];
-					}
-				}
-			}
+				if ( seen.insert( ss.str() ).second ) { ++n_new; }
+
+				bool seen_poly = false;
+				unsigned max_depth = 0;
+				analyzeType( 
+					dt, stats, elSeen, n_basic, n_generic, n_poly, n_agg, seen_poly, max_depth );
+				++stats.n_generic_nesting.at( max_depth );
+			}
+			
 			++pstats.n.at( n );
 			++pstats.n_basic.at( n_basic );
+			++pstats.n_generic.at( n_generic );
 			++pstats.n_poly.at( n_poly );
+			++pstats.n_compound.at( n_agg );
 			if ( n > 0 ) {
 				++pstats.p_basic[ n_basic*100/n ];
+				++pstats.p_generic[ n_generic*100/n ];
 				++pstats.p_poly[ n_poly*100/n ];
-				++pstats.p_new[ n_new*100/n ];
+				++pstats.p_compound[ n_agg*100/n ];
+				if ( n > 1 ) ++pstats.p_new[ (n_new-1)*100/(n-1) ];
 			}
 			++pstats.n_types.at( types.size() );
@@ -183,6 +344,7 @@
 		void analyzeFunc( FunctionType* fnTy, Stats& stats, ArgPackStats& params, ArgPackStats& returns ) {
 			std::unordered_set<std::string> seen;
-			analyze( stats, seen, params, fnTy->get_parameters() );
-			analyze( stats, seen, returns, fnTy->get_returnVals() );
+			std::unordered_set<std::string> elSeen;
+			analyze( stats, seen, elSeen, params, fnTy->get_parameters() );
+			analyze( stats, seen, elSeen, returns, fnTy->get_returnVals() );
 		}
 
@@ -210,5 +372,5 @@
 			}
 
-			Stats& stats = for_linkage[ decl->get_linkage() ];
+			Stats& stats = for_linkage[ ind_for_linkage[ decl->get_linkage() ] ];
 
 			++stats.n_decls;
@@ -272,10 +434,10 @@
 		template<typename F>
 		void printAllHisto( const std::string& name, F extract ) {
-			VectorMap<unsigned> histos[LinkageSpec::NoOfSpecs];
+			VectorMap<unsigned> histos[n_named_specs];
 			VectorMap<unsigned> thisto;
 
 			for ( const auto& entry : extract(total) ) { ++thisto.at( entry.second ); }
 
-			for ( unsigned i = 0; i < LinkageSpec::NoOfSpecs; ++i ) {
+			for ( unsigned i = 0; i < n_named_specs; ++i ) {
 				// can't be a higher count in one of the sub-histograms than the total
 				histos[i].reserve( thisto.size() );
@@ -295,10 +457,10 @@
 		template<typename F>
 		void printAllSparseHisto( const std::string& name, F extract ) {
-			std::map<unsigned, unsigned> histos[LinkageSpec::NoOfSpecs];
+			std::map<unsigned, unsigned> histos[n_named_specs];
 			std::map<unsigned, unsigned> thisto;
 
 			for ( const auto& entry : extract(total) ) { ++thisto[ entry.second ]; }
 
-			for ( unsigned i = 0; i < LinkageSpec::NoOfSpecs; ++i ) {
+			for ( unsigned i = 0; i < n_named_specs; ++i ) {
 				for ( const auto& entry : extract(for_linkage[i]) ) { ++histos[i][entry.second]; }
 			}
@@ -307,5 +469,5 @@
 				const auto& key = entry.first;
 				std::cout << "\"" << name << "\"," << key;
-				for ( unsigned i = 0; i < LinkageSpec::NoOfSpecs; ++i ) {
+				for ( unsigned i = 0; i < n_named_specs; ++i ) {
 					auto it = histos[i].find( key );
 					if ( it == histos[i].end() ) std::cout << ",0";
@@ -319,8 +481,12 @@
 		void printAllPack( const std::string& name, F extract ) {
 			printAllMap("n_basic_" + name, [&extract](const Stats& stats) { return extract(stats).n_basic; });
+			printAllMap("n_generic_" + name, [&extract](const Stats& stats) { return extract(stats).n_generic; });
 			printAllMap("n_poly_" + name, [&extract](const Stats& stats) { return extract(stats).n_poly; });
+			printAllMap("n_compound_" + name, [&extract](const Stats& stats) { return extract(stats).n_compound; });
 			printAllMap("n_" + name, [&extract](const Stats& stats) { return extract(stats).n; });
 			printAllMap("%_basic_" + name, [&extract](const Stats& stats) { return extract(stats).p_basic; });
+			printAllMap("%_generic_" + name, [&extract](const Stats& stats) { return extract(stats).p_generic; });
 			printAllMap("%_poly_" + name, [&extract](const Stats& stats) { return extract(stats).p_poly; });
+			printAllMap("%_compound_" + name, [&extract](const Stats& stats) { return extract(stats).p_compound; });
 			printAllMap("n_distinct_types_" + name, [&extract](const Stats& stats) { return extract(stats).n_types; });
 			printAllMap("%_new_types_in_" + name, [&extract](const Stats& stats) { return extract(stats).p_new; });
@@ -342,7 +508,9 @@
 			}
 
-			std::cout << ",,\"intrinsic\",\"Cforall\",\"C\",\"autogen\",\"builtin\",\"TOTAL\"" << std::endl;
+			std::cout << ",,\"intrinsic\",\"Cforall\",\"C\",\"autogen\",\"compiler\",\"builtinCFA\",\"builtinC\",\"other\",\"TOTAL\"" << std::endl;
 
 			printAllMap("n_type_params", [](const Stats& stats) { return stats.n_type_params; });
+			printAllMap("n_generic_params", [](const Stats& stats) { return stats.n_generic_params; });
+			printAllMap("n_generic_nesting", [](const Stats& stats) { return stats.n_generic_nesting; });
 			printAll("n_decls", [](const Stats& stats) { return stats.n_decls; });
 			printAll("unique_names", [](const Stats& stats) { return stats.by_name.size(); });
@@ -351,4 +519,7 @@
 			printAllSparseHisto("basic_type_uses", [](const Stats& stats) { return stats.basic_type_names; });
 			printAllSparseHisto("decls_using_basic_type", [](const Stats& stats) { return stats.basic_type_decls; });
+			printAll("generic_type_names", [](const Stats& stats) { return stats.generic_type_names.size(); });
+			printAllSparseHisto("generic_type_uses", [](const Stats& stats) { return stats.generic_type_names; });
+			printAllSparseHisto("decls_using_generic_type", [](const Stats& stats) { return stats.generic_type_decls; });
 			printAll("compound_type_names", [](const Stats& stats) { return stats.compound_type_names.size(); });
 			printAllSparseHisto("compound_type_uses", [](const Stats& stats) { return stats.compound_type_names; });
@@ -365,4 +536,7 @@
 	};
 
+	const unsigned DeclStats::ind_for_linkage[] 
+		= { 7, 7, 2, 1,   7, 7, 7, 3,   4, 7, 6, 5,   7, 7, 7, 0 };
+
 	void printDeclStats( std::list< Declaration * > &translationUnit ) {
 		DeclStats stats;
