- Notifications
You must be signed in to change notification settings - Fork749
1783 Implement Interface And Inherit Class#2028
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Runtime.InteropServices; | ||
using System.Runtime.Serialization; | ||
@@ -79,41 +82,80 @@ public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, | ||
BorrowedReference bases = Runtime.PyTuple_GetItem(args, 1); | ||
BorrowedReference dict = Runtime.PyTuple_GetItem(args, 2); | ||
// Extract interface types and base class types. | ||
var interfaces = new List<Type>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. IMHO, repeating the same base interface multiple times should be an error. And it might be, add a test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Test added. | ||
// More than one base type case be declared, but an exception will be thrown | ||
// if more than one is a class/not an interface. | ||
var baseTypes = new List<ClassBase>(); | ||
var baseClassCount = Runtime.PyTuple_Size(bases); | ||
if (baseClassCount == 0) | ||
{ | ||
return Exceptions.RaiseTypeError("zero base classes"); | ||
} | ||
for (nint i = 0; i < baseClassCount; i++) | ||
{ | ||
var baseTypeIt = Runtime.PyTuple_GetItem(bases, (int)i); | ||
if (GetManagedObject(baseTypeIt) is ClassBase classBaseIt) | ||
{ | ||
if (!classBaseIt.type.Valid) | ||
{ | ||
return Exceptions.RaiseTypeError("Invalid type used as a super type."); | ||
} | ||
if (classBaseIt.type.Value.IsInterface) | ||
{ | ||
interfaces.Add(classBaseIt.type.Value); | ||
} | ||
else | ||
{ | ||
baseTypes.Add(classBaseIt); | ||
} | ||
} | ||
else | ||
{ | ||
return Exceptions.RaiseTypeError("Non .NET type used as super class for meta type. This is not supported."); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. What if it is not a .NET class or interface? You can't simply ignore it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Added exceptions here in the latest version. | ||
} | ||
// if the base type count is 0, there might still be interfaces to implement. | ||
if (baseTypes.Count == 0) | ||
{ | ||
baseTypes.Add(new ClassBase(typeof(object))); | ||
} | ||
// Multiple inheritance is not supported, unless the other types are interfaces | ||
if (baseTypes.Count > 1) | ||
{ | ||
var types = string.Join(", ", baseTypes.Select(baseType => baseType.type.Value)); | ||
return Exceptions.RaiseTypeError($"Multiple inheritance with managed classes cannot be used. Types: {types} "); | ||
} | ||
// check if the list of interfaces contains no duplicates. | ||
if (interfaces.Distinct().Count() != interfaces.Count) | ||
{ | ||
// generate a string containing the problematic types. | ||
var duplicateTypes = interfaces.GroupBy(type => type) | ||
.Where(typeGroup => typeGroup.Count() > 1) | ||
.Select(typeGroup => typeGroup.Key); | ||
var duplicateTypesString = string.Join(", ", duplicateTypes); | ||
return Exceptions.RaiseTypeError($"An interface can only be implemented once. Duplicate types: {duplicateTypesString}"); | ||
} | ||
var cb = baseTypes[0]; | ||
try | ||
{ | ||
if (!cb.CanSubclass()) | ||
{ | ||
return Exceptions.RaiseTypeError("delegates, enums and array types cannot be subclassed"); | ||
} | ||
} | ||
catch (SerializationException) | ||
{ | ||
return Exceptions.RaiseTypeError($"Underlying C# Base class {cb.type} has been deleted"); | ||
} | ||
BorrowedReference slots = Runtime.PyDict_GetItem(dict, PyIdentifier.__slots__); | ||
if (slots != null) | ||
@@ -130,10 +172,12 @@ public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, | ||
using var clsDict = new PyDict(dict); | ||
if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__")) | ||
{ | ||
return TypeManager.CreateSubType(name,baseTypes[0], interfaces, clsDict); | ||
} | ||
} | ||
var base_type = Runtime.PyTuple_GetItem(bases, 0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. How can bases be length 0? This should only be called when a C# type is subclassed, right? In this case, it should at least be length 1. | ||
// otherwise just create a basic type without reflecting back into the managed side. | ||
IntPtr func = Util.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_new); | ||
NewReference type = NativeCall.Call_3(func, tp, args, kw); | ||