Index: src/Virtual/ExpandCasts.cc
===================================================================
--- src/Virtual/ExpandCasts.cc	(revision 4a32319e592080097e344a3c2a7c57bf67588d4a)
+++ src/Virtual/ExpandCasts.cc	(revision f19fbbc504e33f9d4eec5177e4abb378bcecf2b7)
@@ -10,6 +10,6 @@
 // Created On       : Mon Jul 24 13:59:00 2017
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue May 26 14:37:00 2020
-// Update Count     : 2
+// Last Modified On : Tue Jul 22 10:04:00 2020
+// Update Count     : 3
 //
 
@@ -24,4 +24,5 @@
 #include "Common/PassVisitor.h"    // for PassVisitor
 #include "Common/SemanticError.h"  // for SemanticError
+#include "SymTab/Mangler.h"        // for mangleType
 #include "SynTree/Declaration.h"   // for ObjectDecl, StructDecl, FunctionDecl
 #include "SynTree/Expression.h"    // for VirtualCastExpr, CastExpr, Address...
@@ -31,4 +32,31 @@
 
 namespace Virtual {
+
+	// Indented until the new ast code gets added.
+
+	/// Maps virtual table types the instance for that type.
+	class VirtualTableMap final {
+		std::unordered_map<std::string, ObjectDecl *> vtable_instances;
+	public:
+		ObjectDecl * insert( ObjectDecl * vtableDecl ) {
+			std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
+			ObjectDecl *& value = vtable_instances[ mangledName ];
+			if ( value ) {
+				if ( vtableDecl->storageClasses.is_extern ) {
+					return nullptr;
+				} else if ( ! value->storageClasses.is_extern ) {
+					return value;
+				}
+			}
+			value = vtableDecl;
+			return nullptr;
+		}
+
+		ObjectDecl * lookup( const Type * vtableType ) {
+			std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
+			const auto it = vtable_instances.find( mangledName );
+			return ( vtable_instances.end() == it ) ? nullptr : it->second;
+		}
+	};
 
 	/* Currently virtual depends on the rather brittle name matching between
@@ -39,4 +67,6 @@
 	 */
 
+	namespace {
+
 	std::string get_vtable_name( std::string const & name ) {
 		return name + "_vtable";
@@ -53,8 +83,4 @@
 	std::string get_vtable_inst_name_root( std::string const & name ) {
 		return get_vtable_name_root( name.substr(1, name.size() - 10 ) );
-	}
-
-	bool is_vtable_name( std::string const & name ) {
-		return (name.substr( name.size() - 7 ) == "_vtable" );
 	}
 
@@ -64,8 +90,10 @@
 	}
 
+	} // namespace
+
 	class VirtualCastCore {
-        std::map<std::string, ObjectDecl *> vtable_instances;
-        FunctionDecl *vcast_decl;
-        StructDecl *pvt_decl;
+		VirtualTableMap vtable_instances;
+		FunctionDecl *vcast_decl;
+		StructDecl *pvt_decl;
 
 		Type * pointer_to_pvt(int level_of_indirection) {
@@ -107,10 +135,17 @@
 	void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
 		if ( is_vtable_inst_name( objectDecl->get_name() ) ) {
-			vtable_instances[objectDecl->get_name()] = objectDecl;
-		}
-	}
-
-	// Better error locations for generated casts.
-	static CodeLocation castLocation( VirtualCastExpr * castExpr ) {
+			if ( ObjectDecl * existing = vtable_instances.insert( objectDecl ) ) {
+				std::string msg = "Repeated instance of virtual table, original found at: ";
+				msg += existing->location.filename;
+				msg += ":" + toString( existing->location.first_line );
+				SemanticError( objectDecl->location, msg );
+			}
+		}
+	}
+
+	namespace {
+
+	/// Better error locations for generated casts.
+	CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
 		if ( castExpr->location.isSet() ) {
 			return castExpr->location;
@@ -124,36 +159,72 @@
 	}
 
+	[[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
+		SemanticError( castLocation( castExpr ), message );
+	}
+
+	/// Get the virtual table type used in a virtual cast.
+	Type * getVirtualTableType( const VirtualCastExpr * castExpr ) {
+		const Type * objectType;
+		if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) {
+			objectType = target->base;
+		} else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) {
+			objectType = target->base;
+		} else {
+			castError( castExpr, "Virtual cast type must be a pointer or reference type." );
+		}
+		assert( objectType );
+
+		const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType );
+		if ( nullptr == structType ) {
+			castError( castExpr, "Virtual cast type must refer to a structure type." );
+		}
+		const StructDecl * structDecl = structType->baseStruct;
+		assert( structDecl );
+
+		const ObjectDecl * fieldDecl = nullptr;
+		if ( 0 < structDecl->members.size() ) {
+			const Declaration * memberDecl = structDecl->members.front();
+			assert( memberDecl );
+			fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
+			if ( fieldDecl && fieldDecl->name != "virtual_table" ) {
+				fieldDecl = nullptr;
+			}
+		}
+		if ( nullptr == fieldDecl ) {
+			castError( castExpr, "Virtual cast type must have a leading virtual_table field." );
+		}
+		const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type );
+		if ( nullptr == fieldType ) {
+			castError( castExpr, "Virtual cast type virtual_table field is not a pointer." );
+		}
+		assert( fieldType->base );
+		auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base );
+		assert( virtualStructType );
+
+		// Here is the type, but if it is polymorphic it will have lost information.
+		// (Always a clone so that it may always be deleted.)
+		StructInstType * virtualType = virtualStructType->clone();
+		if ( ! structType->parameters.empty() ) {
+			deleteAll( virtualType->parameters );
+			virtualType->parameters.clear();
+			cloneAll( structType->parameters, virtualType->parameters );
+		}
+		return virtualType;
+	}
+
+	} // namespace
+
 	Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
-		assertf( castExpr->get_result(), "Virtual Cast target not found before expansion." );
+		assertf( castExpr->result, "Virtual Cast target not found before expansion." );
 
 		assert( vcast_decl );
 		assert( pvt_decl );
 
-		// Get the base type of the pointer/reference.
-		Type * base;
-		Type * result_type = castExpr->result;
-		if ( PointerType * target = dynamic_cast<PointerType *>( result_type ) ) {
-			base = target->base;
-		} else if ( ReferenceType * target = dynamic_cast<ReferenceType *>( result_type ) ) {
-			base = target->base;
-		} else {
+		const Type * vtable_type = getVirtualTableType( castExpr );
+		ObjectDecl * table = vtable_instances.lookup( vtable_type );
+		if ( nullptr == table ) {
 			SemanticError( castLocation( castExpr ),
-				"Virtual cast type must be a pointer or reference type." );
-		}
-
-		StructInstType * target_struct = dynamic_cast<StructInstType *>( base );
-		if ( nullptr == target_struct ) {
-			SemanticError( castLocation( castExpr ),
-				"Virtual cast type must refer to a structure type." );
-		}
-		StructDecl * target_decl = target_struct->get_baseStruct();
-
-		std::map<std::string, ObjectDecl *>::iterator found =
-			vtable_instances.find( get_vtable_inst_name( target_decl->get_name() ) );
-		if ( vtable_instances.end() == found ) {
-			SemanticError( castLocation( castExpr ),
-				"Virtual cast type does not have a virtual table instance." );
-		}
-		ObjectDecl * table = found->second;
+				"Could not find virtual table instance." );
+		}
 
 		Expression * result = new CastExpr(
@@ -174,4 +245,5 @@
 		castExpr->set_result( nullptr );
 		delete castExpr;
+		delete vtable_type;
 		return result;
 	}
Index: tests/exceptions/virtual-cast.cfa
===================================================================
--- tests/exceptions/virtual-cast.cfa	(revision f19fbbc504e33f9d4eec5177e4abb378bcecf2b7)
+++ tests/exceptions/virtual-cast.cfa	(revision f19fbbc504e33f9d4eec5177e4abb378bcecf2b7)
@@ -0,0 +1,76 @@
+// Testing the virtual cast, as part of strict inheritance.
+
+/* IMPORTANT: This test does not repersent the final feature set.
+ * We are missing a number of important aspects such as:
+ * + vtable type generation.
+ * + vtable instance generation, that might use different resolution rules.
+ * + Virtual syntax to force said generation on structures and traits.
+ * + Trait references/pointers that do the virtual_table lookup.
+ */
+
+#include <stdlib.hfa>
+#include <assert.h>
+
+struct alpha_vtable {
+	alpha_vtable const * const parent;
+	char (*code)(void);
+};
+
+struct alpha {
+	alpha_vtable const * virtual_table;
+};
+
+char ret_a(void) {
+	return 'a';
+}
+
+
+
+struct beta_vtable {
+	alpha_vtable const * const parent;
+	char (*code)(void);
+};
+
+struct beta {
+	beta_vtable const * virtual_table;
+};
+
+char ret_b(void) {
+	return 'b';
+}
+
+
+
+struct gamma_vtable {
+	beta_vtable const * const parent;
+	char (*code)(void);
+};
+
+struct gamma {
+	gamma_vtable const * virtual_table;
+};
+
+char ret_g(void) {
+	return 'g';
+}
+
+
+extern "C" {
+	alpha_vtable _alpha_vtable_instance = { 0, ret_a };
+	beta_vtable _beta_vtable_instance = { &_alpha_vtable_instance, ret_b };
+	gamma_vtable _gamma_vtable_instance = { &_beta_vtable_instance, ret_g };
+}
+
+int main (int argc, char * argv[]) {
+
+	gamma * tri = malloc(); tri->virtual_table = &_gamma_vtable_instance;
+	beta * mid = (virtual beta *)tri;
+	assert( 'g' == mid->virtual_table->code() );
+
+	alpha * top = malloc(); top->virtual_table = &_alpha_vtable_instance;
+	mid = (virtual beta *)top;
+	assert( ! mid );
+
+	free(tri);
+	free(top);
+}
Index: tests/exceptions/virtual-poly.cfa
===================================================================
--- tests/exceptions/virtual-poly.cfa	(revision f19fbbc504e33f9d4eec5177e4abb378bcecf2b7)
+++ tests/exceptions/virtual-poly.cfa	(revision f19fbbc504e33f9d4eec5177e4abb378bcecf2b7)
@@ -0,0 +1,79 @@
+// Test virtual casts with polymorphic types.
+
+/* IMPORTANT: The virtual system has not been finalized. However the
+ * exception system does depend on the work-in-progress version currently
+ * supported. That is also why the tests under the exception directory.
+ */
+
+#include <assert.h>
+
+struct mono_base_vtable {
+	mono_base_vtable const * const parent;
+};
+
+struct mono_base {
+	mono_base_vtable const * virtual_table;
+};
+
+forall(otype T)
+struct mono_child_vtable {
+	mono_base_vtable const * const parent;
+};
+
+forall(otype T)
+struct mono_child {
+	mono_child_vtable(T) const * virtual_table;
+};
+
+mono_base_vtable _mono_base_vtable_instance @= { 0 };
+mono_child_vtable(int) _mono_child_vtable_instance @= {
+	&_mono_base_vtable_instance
+};
+
+void mono_poly_test(void) {
+	mono_child(int) child = { &_mono_child_vtable_instance };
+	mono_base * base = (virtual mono_base *)&child;
+	assert(base);
+}
+
+forall(otype U)
+struct poly_base_vtable {
+	poly_base_vtable(U) const * const parent;
+};
+
+forall(otype U)
+struct poly_base {
+	poly_base_vtable(U) const * virtual_table;
+};
+
+forall(otype V)
+struct poly_child_vtable {
+	poly_base_vtable(V) const * const parent;
+};
+
+forall(otype V)
+struct poly_child {
+	poly_child_vtable(V) const * virtual_table;
+};
+
+poly_base_vtable(int) _poly_base_vtable_instance @= { 0 };
+poly_child_vtable(int) _poly_child_vtable_instance @= {
+	&_poly_base_vtable_instance
+};
+/* Resolver bug keeps me from adding these.
+poly_base_vtable(char) _poly_base_vtable_instance @= { 0 };
+poly_child_vtable(char) _poly_child_vtable_instance @= {
+	&_poly_base_vtable_instance
+};
+*/
+
+void poly_poly_test() {
+	poly_child(int) child = { &_poly_child_vtable_instance };
+	poly_base(int) * base = (virtual poly_base(int) *)&child;
+	assert(base);
+}
+
+int main(void) {
+	mono_poly_test();
+	poly_poly_test();
+}
Index: sts/zombies/virtualCast.cfa
===================================================================
--- tests/zombies/virtualCast.cfa	(revision 4a32319e592080097e344a3c2a7c57bf67588d4a)
+++ 	(revision )
@@ -1,76 +1,0 @@
-// Testing the virtual cast, as part of strict inheritance.
-
-/* IMPORTANT: This test does not repersent the final feature set.
- * We are missing a number of important aspects such as:
- * + vtable type generation.
- * + vtable instance generation, that might use different resolution rules.
- * + Virtual syntax to force said generation on structures and traits.
- * + Trait references/pointers that do the virtual_table lookup.
- */
-
-#include <stdlib.hfa>
-#include <assert.h>
-
-struct alpha_vtable {
-	alpha_vtable const * const parent;
-	char (*code)(void);
-};
-
-struct alpha {
-	alpha_vtable const * virtual_table;
-};
-
-char ret_a(void) {
-	return 'a';
-}
-
-
-
-struct beta_vtable {
-	alpha_vtable const * const parent;
-	char (*code)(void);
-};
-
-struct beta {
-	beta_vtable const * virtual_table;
-};
-
-char ret_b(void) {
-	return 'b';
-}
-
-
-
-struct gamma_vtable {
-	beta_vtable const * const parent;
-	char (*code)(void);
-};
-
-struct gamma {
-	gamma_vtable const * virtual_table;
-};
-
-char ret_g(void) {
-	return 'g';
-}
-
-
-extern "C" {
-	alpha_vtable _alpha_vtable_instance = { 0, ret_a };
-	beta_vtable _beta_vtable_instance = { &_alpha_vtable_instance, ret_b };
-	gamma_vtable _gamma_vtable_instance = { &_beta_vtable_instance, ret_g };
-}
-
-int main (int argc, char * argv[]) {
-
-	gamma * tri = malloc(); tri->virtual_table = &_gamma_vtable_instance;
-	beta * mid = (virtual beta *)tri;
-	assert( 'g' == mid->virtual_table->code() );
-
-	alpha * top = malloc(); top->virtual_table = &_alpha_vtable_instance;
-	mid = (virtual beta *)top;
-	assert( ! mid );
-
-	free(tri);
-	free(top);
-}
