Index: src/Virtual/ExpandCasts.cc
===================================================================
--- src/Virtual/ExpandCasts.cc	(revision c19bc90112fb552e6efe8c9bc93732c41f0734b7)
+++ src/Virtual/ExpandCasts.cc	(revision e262b5e7ae4607ee657657e844dbceec3e42e659)
@@ -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;
 	}
