private static Type GetBaseTypeFromUserType(PythonType curBasePythonType, IList <Type> baseInterfaces, Type curTypeToExtend) { Queue <PythonType> processing = new Queue <PythonType>(); processing.Enqueue(curBasePythonType); do { PythonType walking = processing.Dequeue(); foreach (PythonType dt in walking.BaseTypes) { if (dt.ExtensionType == curTypeToExtend || curTypeToExtend.IsSubclassOf(dt.ExtensionType)) { continue; } if (dt.ExtensionType.IsInterface) { baseInterfaces.Add(dt.ExtensionType); } else if (NewTypeMaker.IsInstanceType(dt.ExtensionType)) { processing.Enqueue(dt); } else if (!dt.IsOldClass) { curTypeToExtend = null; break; } } } while (processing.Count > 0); return(curTypeToExtend); }
public override Type GetTypesToExtend(out IList <Type> interfacesToExtend) { interfacesToExtend = new List <Type>(); foreach (object b in bases) { if (b is OldClass) { continue; } PythonType baseType = b as PythonType; IList <Type> baseTypeInterfaces; baseType.GetTypesToExtend(out baseTypeInterfaces); foreach (Type baseTypeInterface in baseTypeInterfaces) { interfacesToExtend.Add(baseTypeInterface); } } // We dont use type.GetInterfaces() as it contains all the interfaces that are added by NewTypeMaker, // as well as all the interfaces implemented by type.BaseType. Instead, we only want the new set of // interfaces that need to be implemented by the new instance type. Debug.Assert(interfacesToExtend.Count < type.GetInterfaces().Length); // "type" is the instance type used for instances of this type. This will be a type created by NewTypeMaker. Debug.Assert(NewTypeMaker.IsInstanceType(type)); // Its BaseType will the CLI type that needs to be inherited by instance types used by other UserTypes inheriting // from the current UserType. For pure Python types, this will be System.Object. Debug.Assert(!NewTypeMaker.IsInstanceType(type.BaseType)); return(type.BaseType); }
/// <summary> /// "bases" contains a set of PythonTypes. These can include types defined in Python (say cpy1, cpy2), /// CLI types (say cCLI1, cCLI2), and CLI interfaces (say iCLI1, iCLI2). Here are some /// examples of how this works: /// /// (bases) => baseType, {interfaceTypes} /// /// (cpy1) => System.Object, {} /// (cpy1, cpy2) => System.Object, {} /// (cpy1, cCLI1, iCLI1, iCLI2) => cCLI1, {iCLI1, iCLI2} /// [some type that satisfies the line above] => /// cCLI1, {iCLI1, iCLI2} /// (cCLI1, cCLI2) => error /// </summary> public static NewTypeInfo GetTypeInfo(string typeName, PythonTuple bases) { List <Type> interfaceTypes = new List <Type>(); Type baseCLIType = typeof(object); // Pure Python object instances inherit from System.Object PythonType basePythonType = null; foreach (PythonType curBasePythonType in GetPythonTypes(typeName, bases)) { // discover the initial base/interfaces IList <Type> baseInterfaces = ReflectionUtils.EmptyTypes; Type curTypeToExtend = curBasePythonType.ExtensionType; if (curBasePythonType.ExtensionType.IsInterface) { baseInterfaces = new Type[] { curTypeToExtend }; curTypeToExtend = typeof(object); } else if (NewTypeMaker.IsInstanceType(curTypeToExtend)) { baseInterfaces = new List <Type>(); curTypeToExtend = GetBaseTypeFromUserType(curBasePythonType, baseInterfaces, curTypeToExtend.BaseType); } if (curTypeToExtend == null || typeof(BuiltinFunction).IsAssignableFrom(curTypeToExtend) || typeof(PythonFunction).IsAssignableFrom(curTypeToExtend)) { throw PythonOps.TypeError(typeName + ": {0} is not an acceptable base type", curBasePythonType.Name); } if (curTypeToExtend.ContainsGenericParameters) { throw PythonOps.TypeError(typeName + ": cannot inhert from open generic instantiation {0}. Only closed instantiations are supported.", curBasePythonType); } foreach (Type interfaceType in baseInterfaces) { if (interfaceType.ContainsGenericParameters) { throw PythonOps.TypeError(typeName + ": cannot inhert from open generic instantiation {0}. Only closed instantiations are supported.", interfaceType); } // collecting all the interfaces because we override them all. interfaceTypes.Add(interfaceType); } // if we're not extending something already in our existing base classes type hierarchy // then we better be in some esoteric __slots__ situation if (!baseCLIType.IsSubclassOf(curTypeToExtend)) { if (baseCLIType != typeof(object) && baseCLIType != curTypeToExtend && (!baseCLIType.IsDefined(typeof(DynamicBaseTypeAttribute), false) && !curTypeToExtend.IsSubclassOf(baseCLIType))) { throw PythonOps.TypeError( typeName + ": can only extend one CLI or builtin type, not both {0} (for {1}) and {2} (for {3})", baseCLIType.FullName, basePythonType, curTypeToExtend.FullName, curBasePythonType); } // we have a new base type baseCLIType = curTypeToExtend; basePythonType = curBasePythonType; } } return(new NewTypeInfo(baseCLIType, interfaceTypes.Count == 0 ? ReflectionUtils.EmptyTypes : interfaceTypes.ToArray())); }