public static VTable ConstructVTable(TypeDef typeDef, VTableStorage storage) { var ret = new VTable(typeDef); var slotDict = new Dictionary<VTableSignature, List<VTableSlot>>(); // Partition II 12.2 // Interfaces foreach (InterfaceImpl iface in typeDef.Interfaces) { VTable ifaceVTbl = storage.GetVTable(iface.Interface); if (ifaceVTbl != null) ret.Inherit(ifaceVTbl, slotDict); } // Base type VTable baseVTbl = storage.GetVTable(typeDef.GetBaseTypeThrow()); if (baseVTbl != null) ret.Inherit(baseVTbl, slotDict); List<MethodDef> virtualMethods = typeDef.Methods.Where(method => method.IsVirtual).ToList(); var methodsProcessed = new HashSet<MethodDef>(); // MethodImpls (Partition II 22.27) foreach (MethodDef method in virtualMethods) foreach (MethodOverride impl in method.Overrides) { Debug.Assert(impl.MethodBody == method); MethodDef targetMethod = impl.MethodDeclaration.ResolveThrow(); VTableSignature sig = VTableSignature.FromMethod(impl.MethodDeclaration); Debug.Assert(slotDict.ContainsKey(sig)); var methodSlot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), VTableSignature.FromMethod(method)); ret.Override(slotDict, sig, methodSlot, targetMethod); methodsProcessed.Add(method); } // Normal override foreach (MethodDef method in virtualMethods) { VTableSignature sig = VTableSignature.FromMethod(method); var methodSlot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), sig); if (slotDict.ContainsKey(sig) && slotDict[sig].Count > 0) { ret.Override(slotDict, sig, methodSlot); methodsProcessed.Add(method); } } // Remaining methods foreach (MethodDef method in typeDef.Methods.Where(method => method.IsVirtual).Except(methodsProcessed)) { var slot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), VTableSignature.FromMethod(method)); if (method.IsFinal) ret.Finals.Add(slot); else { Debug.Assert(!ret.Slots.Any(s => s.MethodDef == method)); ret.Slots.Add(slot); } } return ret; }
public VTable GetVTable(ITypeDefOrRef type) { if (type == null) { return(null); } if (type is TypeDef) { return(GetOrConstruct((TypeDef)type)); } else if (type is TypeRef) { return(GetOrConstruct(((TypeRef)type).ResolveThrow())); } else if (type is TypeSpec) { TypeSig sig = ((TypeSpec)type).TypeSig; if (sig is TypeDefOrRefSig) { TypeDef typeDef = ((TypeDefOrRefSig)sig).TypeDefOrRef.ResolveTypeDefThrow(); return(GetOrConstruct(typeDef)); } else if (sig is GenericInstSig) { var genInst = (GenericInstSig)sig; TypeDef openType = genInst.GenericType.TypeDefOrRef.ResolveTypeDefThrow(); VTable vTable = GetOrConstruct(openType); return(ResolveGenericArgument(openType, genInst, vTable)); } else { throw new NotSupportedException("Unexpected type: " + type.ToString()); } } else { throw new UnreachableException(); } }
static void Inherits(VTableConstruction vTbl, VTable baseVTbl) { foreach (VTableSlot slot in baseVTbl.Slots) { vTbl.AllSlots.Add(slot); // It's possible to have same signature in multiple slots, // when a derived type shadow the base type using newslot. // In this case, use the derived type's slot in SlotsMap. // The derived type's slots are always at a later position // than the base type, so it would naturally 'override' // their position in SlotsMap. vTbl.SlotsMap[slot.Signature] = slot; } // This is the step 1 of 12.2 algorithm -- copy the base interface implementation. foreach (KeyValuePair <TypeSig, IList <VTableSlot> > iface in baseVTbl.InterfaceSlots) { Debug.Assert(!vTbl.InterfaceSlots.ContainsKey(iface.Key)); vTbl.InterfaceSlots.Add(iface.Key, iface.Value.ToDictionary(slot => slot.Signature, slot => slot)); } }
private static VTable ResolveGenericArgument(TypeDef openType, GenericInstSig genInst, VTable vTable) { Debug.Assert(openType == vTable.Type); var ret = new VTable(openType); ret.GenericArguments = genInst.GenericArguments; foreach (VTableSlot slot in vTable.Slots) { MethodSig newSig = GenericArgumentResolver.Resolve(slot.Signature.MethodSig, genInst.GenericArguments); TypeSig newDecl = slot.DeclaringType; if (new SigComparer().Equals(newDecl, openType)) { newDecl = new GenericInstSig((ClassOrValueTypeSig)openType.ToTypeSig(), genInst.GenericArguments.ToArray()); } else { newDecl = GenericArgumentResolver.Resolve(newDecl, genInst.GenericArguments); } ret.Slots.Add(new VTableSlot(ret, slot.MethodDef, newDecl, new VTableSignature(genInst, newSig, slot.Signature.Name)).Override(slot)); } return(ret); }
private void Inherit(VTable parent, Dictionary <VTableSignature, List <VTableSlot> > slotDict) { foreach (VTableSlot slot in parent.Slots) { List <VTableSlot> slotList; if (slotDict.TryGetValue(slot.Signature, out slotList)) { if (slotList.Count > 0) { if (slotList.All(baseSlot => baseSlot.MethodDef.DeclaringType.IsInterface)) { // Base slot is interface method => add together if (!slotList.Any(baseSlot => baseSlot.Signature == slot.Signature && new SigComparer().Equals(baseSlot.DeclaringType, slot.DeclaringType))) { slotList.Add(slot); Slots.Add(slot); } } else { throw new UnreachableException(); } } else { slotList.Add(slot); Slots.Add(slot); } } else { slotDict.AddListEntry(slot.Signature, slot); Slots.Add(slot); } } }
private static VTable ResolveGenericArgument(TypeDef openType, GenericInstSig genInst, VTable vTable) { Debug.Assert(openType == vTable.Type); var ret = new VTable(openType); ret.GenericArguments = genInst.GenericArguments; foreach (VTableSlot slot in vTable.Slots) { MethodSig newSig = GenericArgumentResolver.Resolve(slot.Signature.MethodSig, genInst.GenericArguments); TypeSig newDecl = slot.DeclaringType; if (new SigComparer().Equals(newDecl, openType)) newDecl = new GenericInstSig((ClassOrValueTypeSig)openType.ToTypeSig(), genInst.GenericArguments.ToArray()); else newDecl = GenericArgumentResolver.Resolve(newDecl, genInst.GenericArguments); ret.Slots.Add(new VTableSlot(ret, slot.MethodDef, newDecl, new VTableSignature(genInst, newSig, slot.Signature.Name)).Override(slot)); } return ret; }
internal VTableSlot(VTable vTable, MethodDef def, TypeSig decl, VTableSignature signature) { VTable = vTable; MethodDef = def; DeclaringType = decl; Signature = signature; Overrides = new List<VTableSlot>(); }
private void Inherit(VTable parent, Dictionary<VTableSignature, List<VTableSlot>> slotDict) { foreach (VTableSlot slot in parent.Slots) { List<VTableSlot> slotList; if (slotDict.TryGetValue(slot.Signature, out slotList)) { if (slotList.Count > 0) { if (slotList.All(baseSlot => baseSlot.MethodDef.DeclaringType.IsInterface)) { // Base slot is interface method => add together if (!slotList.Any(baseSlot => baseSlot.Signature == slot.Signature && new SigComparer().Equals(baseSlot.DeclaringType, slot.DeclaringType))) { slotList.Add(slot); Slots.Add(slot); } } else throw new UnreachableException(); } else { slotList.Add(slot); Slots.Add(slot); } } else { slotDict.AddListEntry(slot.Signature, slot); Slots.Add(slot); } } }
public static VTable ConstructVTable(TypeDef typeDef, VTableStorage storage) { var ret = new VTable(typeDef); var slotDict = new Dictionary<VTableSignature, List<VTableSlot>>(); // Partition II 12.2 // Interfaces foreach (InterfaceImpl iface in typeDef.Interfaces) { VTable ifaceVTbl = storage.GetVTable(iface.Interface); if (ifaceVTbl != null) ret.Inherit(ifaceVTbl, slotDict); } // Base type VTable baseVTbl = storage.GetVTable(typeDef.GetBaseTypeThrow()); if (baseVTbl != null) ret.Inherit(baseVTbl, slotDict); List<MethodDef> virtualMethods = typeDef.Methods.Where(method => method.IsVirtual).ToList(); var methodsProcessed = new HashSet<MethodDef>(); // MethodImpls (Partition II 22.27) foreach (MethodDef method in virtualMethods) foreach (MethodOverride impl in method.Overrides) { Debug.Assert(impl.MethodBody == method); MethodDef targetMethod = impl.MethodDeclaration.ResolveThrow(); VTableSignature sig = VTableSignature.FromMethod(impl.MethodDeclaration); Debug.Assert(slotDict.ContainsKey(sig)); var methodSlot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), VTableSignature.FromMethod(method)); if (slotDict.ContainsKey(sig) && slotDict[sig].Count > 0) { ret.Override(slotDict, sig, methodSlot, targetMethod); methodsProcessed.Add(method); } } // Normal override foreach (MethodDef method in virtualMethods) { VTableSignature sig = VTableSignature.FromMethod(method); var methodSlot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), sig); if (slotDict.ContainsKey(sig) && slotDict[sig].Count > 0) { ret.Override(slotDict, sig, methodSlot); methodsProcessed.Add(method); } } // Remaining methods foreach (MethodDef method in typeDef.Methods.Where(method => method.IsVirtual).Except(methodsProcessed)) { foreach (var remainingSlot in slotDict.Keys.Where(key => key.InterfaceType != null)) { // If there is a remaining slot for an interface method which has the same name and signature as an unprocessed method, // allow the method to override the slot. // This is necessary because public methods which implement interface methods do not have an InterfaceType in their signature, // but the keys of "slotDict" which were added for interface methods *do* have InterfaceType in their signature. Therefore, // these slots are not filled by the "Normal override" loop above. if (new SigComparer().Equals(remainingSlot.MethodSig, method.MethodSig) && remainingSlot.Name.Equals(method.Name, StringComparison.Ordinal)) { var methodSlot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), remainingSlot); ret.Override(slotDict, remainingSlot, methodSlot); methodsProcessed.Add(method); goto next; } } var slot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), VTableSignature.FromMethod(method)); if (method.IsFinal) ret.Finals.Add(slot); else { Debug.Assert(!ret.Slots.Any(s => s.MethodDef == method)); ret.Slots.Add(slot); } next: continue; } return ret; }
static VTable ResolveGenericArgument(TypeDef openType, GenericInstSig genInst, VTable vTable) { Debug.Assert(new SigComparer().Equals(openType, vTable.Type)); var ret = new VTable(genInst); foreach (VTableSlot slot in vTable.Slots) { ret.Slots.Add(ResolveSlot(openType, slot, genInst.GenericArguments)); } foreach (KeyValuePair <TypeSig, IList <VTableSlot> > iface in vTable.InterfaceSlots) { ret.InterfaceSlots.Add(GenericArgumentResolver.Resolve(iface.Key, genInst.GenericArguments), iface.Value.Select(slot => ResolveSlot(openType, slot, genInst.GenericArguments)).ToList()); } return(ret); }
static void Implements(VTableConstruction vTbl, Dictionary <VTableSignature, MethodDef> virtualMethods, VTable ifaceVTbl, TypeSig iface) { // This is the step 2 of 12.2 algorithm -- use virtual newslot methods for explicit implementation. Func <VTableSlot, VTableSlot> implLookup = slot => { if (virtualMethods.TryGetValue(slot.Signature, out MethodDef impl) && impl.IsNewSlot && !impl.DeclaringType.IsInterface) { // Interface methods cannot implements base interface methods. // The Overrides of interface slots should directly points to the root interface slot VTableSlot targetSlot = slot; while (targetSlot.Overrides != null && !targetSlot.MethodDef.DeclaringType.IsInterface) { targetSlot = targetSlot.Overrides; } Debug.Assert(targetSlot.MethodDef.DeclaringType.IsInterface); return(targetSlot.OverridedBy(impl)); } return(slot); }; if (vTbl.InterfaceSlots.ContainsKey(iface)) { vTbl.InterfaceSlots[iface] = vTbl.InterfaceSlots[iface].Values.ToDictionary( slot => slot.Signature, implLookup); } else { vTbl.InterfaceSlots.Add(iface, ifaceVTbl.Slots.ToDictionary( slot => slot.Signature, implLookup)); } foreach (KeyValuePair <TypeSig, IList <VTableSlot> > baseIface in ifaceVTbl.InterfaceSlots) { if (vTbl.InterfaceSlots.ContainsKey(baseIface.Key)) { vTbl.InterfaceSlots[baseIface.Key] = vTbl.InterfaceSlots[baseIface.Key].Values.ToDictionary( slot => slot.Signature, implLookup); } else { vTbl.InterfaceSlots.Add(baseIface.Key, baseIface.Value.ToDictionary( slot => slot.Signature, implLookup)); } } }
public static VTable ConstructVTable(TypeDef typeDef, VTableStorage storage) { var ret = new VTable(typeDef.ToTypeSig()); var virtualMethods = typeDef.Methods .Where(method => method.IsVirtual) .ToDictionary( method => VTableSignature.FromMethod(method), method => method ); // See Partition II 12.2 for implementation algorithm var vTbl = new VTableConstruction(); // Inherits base type's slots VTable baseVTbl = storage.GetVTable(typeDef.GetBaseTypeThrow()); if (baseVTbl != null) { Inherits(vTbl, baseVTbl); } // Explicit interface implementation foreach (InterfaceImpl iface in typeDef.Interfaces) { VTable ifaceVTbl = storage.GetVTable(iface.Interface); if (ifaceVTbl != null) { Implements(vTbl, virtualMethods, ifaceVTbl, iface.Interface.ToTypeSig()); } } // Normal interface implementation if (!typeDef.IsInterface) { // Interface methods cannot implements base interface methods. foreach (Dictionary <VTableSignature, VTableSlot> iface in vTbl.InterfaceSlots.Values) { foreach (KeyValuePair <VTableSignature, VTableSlot> entry in iface.ToList()) { if (!entry.Value.MethodDef.DeclaringType.IsInterface) { continue; } if (virtualMethods.TryGetValue(entry.Key, out MethodDef impl)) { iface[entry.Key] = entry.Value.OverridedBy(impl); } else if (vTbl.SlotsMap.TryGetValue(entry.Key, out VTableSlot implSlot)) { iface[entry.Key] = entry.Value.OverridedBy(implSlot.MethodDef); } } } } // Normal overrides foreach (KeyValuePair <VTableSignature, MethodDef> method in virtualMethods) { VTableSlot slot; if (method.Value.IsNewSlot) { slot = new VTableSlot(method.Value, typeDef.ToTypeSig(), method.Key); } else { if (vTbl.SlotsMap.TryGetValue(method.Key, out slot)) { Debug.Assert(!slot.MethodDef.IsFinal); slot = slot.OverridedBy(method.Value); } else { slot = new VTableSlot(method.Value, typeDef.ToTypeSig(), method.Key); } } vTbl.SlotsMap[method.Key] = slot; vTbl.AllSlots.Add(slot); } // MethodImpls foreach (KeyValuePair <VTableSignature, MethodDef> method in virtualMethods) { foreach (MethodOverride impl in method.Value.Overrides) { Debug.Assert(impl.MethodBody == method.Value); MethodDef targetMethod = impl.MethodDeclaration.ResolveThrow(); if (targetMethod.DeclaringType.IsInterface) { var iface = impl.MethodDeclaration.DeclaringType.ToTypeSig(); CheckKeyExist(storage, vTbl.InterfaceSlots, iface, "MethodImpl Iface"); Dictionary <VTableSignature, VTableSlot> ifaceVTbl = vTbl.InterfaceSlots[iface]; var signature = VTableSignature.FromMethod(impl.MethodDeclaration); CheckKeyExist(storage, ifaceVTbl, signature, "MethodImpl Iface Sig"); VTableSlot targetSlot = ifaceVTbl[signature]; // The Overrides of interface slots should directly points to the root interface slot while (targetSlot.Overrides != null) { targetSlot = targetSlot.Overrides; } Debug.Assert(targetSlot.MethodDef.DeclaringType.IsInterface); ifaceVTbl[targetSlot.Signature] = targetSlot.OverridedBy(method.Value); } else { VTableSlot targetSlot = vTbl.AllSlots.Single(slot => slot.MethodDef == targetMethod); CheckKeyExist(storage, vTbl.SlotsMap, targetSlot.Signature, "MethodImpl Normal Sig"); targetSlot = vTbl.SlotsMap[targetSlot.Signature]; // Use the most derived slot // Maybe implemented by above processes --- this process should take priority while (targetSlot.MethodDef.DeclaringType == typeDef) { targetSlot = targetSlot.Overrides; } vTbl.SlotsMap[targetSlot.Signature] = targetSlot.OverridedBy(method.Value); } } } // Populate result V-table ret.InterfaceSlots = vTbl.InterfaceSlots.ToDictionary( kvp => kvp.Key, kvp => (IList <VTableSlot>)kvp.Value.Values.ToList()); foreach (VTableSlot slot in vTbl.AllSlots) { ret.Slots.Add(slot); } return(ret); }
public static VTable ConstructVTable(TypeDef typeDef, VTableStorage storage) { var ret = new VTable(typeDef); var slotDict = new Dictionary <VTableSignature, List <VTableSlot> >(); // Partition II 12.2 // Interfaces foreach (InterfaceImpl iface in typeDef.Interfaces) { VTable ifaceVTbl = storage.GetVTable(iface.Interface); if (ifaceVTbl != null) { ret.Inherit(ifaceVTbl, slotDict); } } // Base type VTable baseVTbl = storage.GetVTable(typeDef.GetBaseTypeThrow()); if (baseVTbl != null) { ret.Inherit(baseVTbl, slotDict); } List <MethodDef> virtualMethods = typeDef.Methods.Where(method => method.IsVirtual).ToList(); var methodsProcessed = new HashSet <MethodDef>(); // MethodImpls (Partition II 22.27) foreach (MethodDef method in virtualMethods) { foreach (MethodOverride impl in method.Overrides) { Debug.Assert(impl.MethodBody == method); MethodDef targetMethod = impl.MethodDeclaration.ResolveThrow(); VTableSignature sig = VTableSignature.FromMethod(impl.MethodDeclaration); Debug.Assert(slotDict.ContainsKey(sig)); var methodSlot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), VTableSignature.FromMethod(method)); if (slotDict.ContainsKey(sig) && slotDict[sig].Count > 0) { ret.Override(slotDict, sig, methodSlot, targetMethod); methodsProcessed.Add(method); } } } // Normal override foreach (MethodDef method in virtualMethods) { VTableSignature sig = VTableSignature.FromMethod(method); var methodSlot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), sig); if (slotDict.ContainsKey(sig) && slotDict[sig].Count > 0) { ret.Override(slotDict, sig, methodSlot); methodsProcessed.Add(method); } } // Remaining methods foreach (MethodDef method in typeDef.Methods.Where(method => method.IsVirtual).Except(methodsProcessed)) { foreach (var remainingSlot in slotDict.Keys.Where(key => key.InterfaceType != null)) { // If there is a remaining slot for an interface method which has the same name and signature as an unprocessed method, // allow the method to override the slot. // This is necessary because public methods which implement interface methods do not have an InterfaceType in their signature, // but the keys of "slotDict" which were added for interface methods *do* have InterfaceType in their signature. Therefore, // these slots are not filled by the "Normal override" loop above. if (new SigComparer().Equals(remainingSlot.MethodSig, method.MethodSig) && remainingSlot.Name.Equals(method.Name, StringComparison.Ordinal)) { var methodSlot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), remainingSlot); ret.Override(slotDict, remainingSlot, methodSlot); methodsProcessed.Add(method); goto next; } } var slot = new VTableSlot(ret, method, method.DeclaringType.ToTypeSig(), VTableSignature.FromMethod(method)); if (method.IsFinal) { ret.Finals.Add(slot); } else { Debug.Assert(!ret.Slots.Any(s => s.MethodDef == method)); ret.Slots.Add(slot); } next: continue; } return(ret); }
public static VTable ConstructVTable(TypeDef typeDef, VTableStorage storage) { var ret = new VTable(typeDef.ToTypeSig()); var virtualMethods = typeDef.Methods .Where(method => method.IsVirtual) .ToDictionary( method => VTableSignature.FromMethod(method), method => method ); // See Partition II 12.2 for implementation algorithm VTableConstruction vTbl = new VTableConstruction(); // Inherits base type's slots VTable baseVTbl = storage.GetVTable(typeDef.GetBaseTypeThrow()); if (baseVTbl != null) { Inherits(vTbl, baseVTbl); } // Explicit interface implementation foreach (InterfaceImpl iface in typeDef.Interfaces) { VTable ifaceVTbl = storage.GetVTable(iface.Interface); if (ifaceVTbl != null) { Implements(vTbl, virtualMethods, ifaceVTbl, iface.Interface.ToTypeSig()); } } // Normal interface implementation if (!typeDef.IsInterface) { // Interface methods cannot implements base interface methods. foreach (var interfaceTypeSig in vTbl.InterfaceSlots.Keys.ToList()) { var slots = vTbl.InterfaceSlots[interfaceTypeSig]; if (slots.Select(g => g.Key) .Any(sig => virtualMethods.ContainsKey(sig) || vTbl.SlotsMap.ContainsKey(sig))) { // Something has a new signature. We need to rewrite the whole thing. // This is the step 1 of 12.2 algorithm -- find implementation for still empty slots. // Note that it seems we should include newslot methods as well, despite what the standard said. slots = slots .SelectMany(g => g.Select(slot => (g.Key, Slot: slot))) .ToLookup(t => t.Key, t => { if (!t.Slot.MethodDef.DeclaringType.IsInterface) { return(t.Slot); } if (virtualMethods.TryGetValue(t.Key, out var impl)) { return(t.Slot.OverridedBy(impl)); } if (vTbl.SlotsMap.TryGetValue(t.Key, out var implSlot)) { return(t.Slot.OverridedBy(implSlot.MethodDef)); } return(t.Slot); }); vTbl.InterfaceSlots[interfaceTypeSig] = slots; } } } // Normal overrides foreach (var method in virtualMethods) { VTableSlot slot; if (method.Value.IsNewSlot) { slot = new VTableSlot(method.Value, typeDef.ToTypeSig(), method.Key); } else { if (vTbl.SlotsMap.TryGetValue(method.Key, out slot)) { Debug.Assert(!slot.MethodDef.IsFinal); slot = slot.OverridedBy(method.Value); } else { slot = new VTableSlot(method.Value, typeDef.ToTypeSig(), method.Key); } } vTbl.SlotsMap[method.Key] = slot; vTbl.AllSlots.Add(slot); } // MethodImpls foreach (var method in virtualMethods) { foreach (var impl in method.Value.Overrides) { Debug.Assert(impl.MethodBody == method.Value); MethodDef targetMethod = impl.MethodDeclaration.ResolveThrow(); if (targetMethod.DeclaringType.IsInterface) { var iface = impl.MethodDeclaration.DeclaringType.ToTypeSig(); CheckKeyExist(storage, vTbl.InterfaceSlots, iface, "MethodImpl Iface"); var ifaceVTbl = vTbl.InterfaceSlots[iface]; var signature = VTableSignature.FromMethod(impl.MethodDeclaration); CheckKeyExist(storage, ifaceVTbl, signature, "MethodImpl Iface Sig"); vTbl.InterfaceSlots[iface] = ifaceVTbl .SelectMany(g => g.Select(slot => (g.Key, Slot: slot))) .ToLookup(t => t.Key, t => { if (!t.Key.Equals(signature)) { return(t.Slot); } var targetSlot = t.Slot; while (targetSlot.Overrides != null) { targetSlot = targetSlot.Overrides; } Debug.Assert(targetSlot.MethodDef.DeclaringType.IsInterface); Debug.Assert(targetSlot.Signature.Equals(t.Slot.Signature)); return(targetSlot.OverridedBy(method.Value)); }); } else { var targetSlot = vTbl.AllSlots.Single(slot => slot.MethodDef == targetMethod); CheckKeyExist(storage, vTbl.SlotsMap, targetSlot.Signature, "MethodImpl Normal Sig"); targetSlot = vTbl.SlotsMap[targetSlot.Signature]; // Use the most derived slot // Maybe implemented by above processes --- this process should take priority while (targetSlot.MethodDef.DeclaringType == typeDef) { targetSlot = targetSlot.Overrides; } vTbl.SlotsMap[targetSlot.Signature] = targetSlot.OverridedBy(method.Value); } } } // Populate result V-table ret.InterfaceSlots = vTbl.InterfaceSlots.ToDictionary( kvp => kvp.Key, kvp => (IList <VTableSlot>)kvp.Value.SelectMany(g => g).ToList(), TypeEqualityComparer.Instance); foreach (var slot in vTbl.AllSlots) { ret.Slots.Add(slot); } return(ret); }