/DICK.B1/IronPython/Runtime/Types/NewTypeInfo.cs
C# | 181 lines | 111 code | 28 blank | 42 comment | 37 complexity | 0388d19c4d43fe96304a162ab1c9e9b6 MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- using System;
- using System.Collections.Generic;
-
- using IronPython.Runtime.Operations;
-
- namespace IronPython.Runtime.Types {
- /// <summary>
- /// TypeInfo captures the minimal CLI information required by NewTypeMaker for a Python object
- /// that inherits from a CLI type.
- /// </summary>
- internal class NewTypeInfo {
- // The CLI base-type.
- private readonly Type _baseType;
-
- private readonly IList<Type> _interfaceTypes;
- private Nullable<int> _hash;
-
- public NewTypeInfo(Type baseType, IList<Type> interfaceTypes) {
- _baseType = baseType;
- _interfaceTypes = interfaceTypes;
- }
-
- /// <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 = Type.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 ? Type.EmptyTypes : interfaceTypes.ToArray());
- }
-
- /// <summary>
- /// Filters out old-classes and throws if any non-types are included, returning a
- /// yielding the remaining PythonType objects.
- /// </summary>
- private static IEnumerable<PythonType> GetPythonTypes(string typeName, ICollection<object> bases) {
- foreach (object curBaseType in bases) {
- PythonType curBasePythonType = curBaseType as PythonType;
- if (curBasePythonType == null) {
- if (curBaseType is OldClass)
- continue;
- throw PythonOps.TypeError(typeName + ": unsupported base type for new-style class " + curBaseType);
- }
-
- yield return curBasePythonType;
- }
- }
-
- 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 Type BaseType {
- get { return _baseType; }
- }
-
- public IList<Type> InterfaceTypes {
- get { return _interfaceTypes; }
- }
-
- public override int GetHashCode() {
- if (_hash == null) {
- int hashCode = _baseType.GetHashCode();
- for (int i = 0; i < _interfaceTypes.Count; i++) {
- hashCode ^= _interfaceTypes[i].GetHashCode();
- }
-
- _hash = hashCode;
- }
-
- return _hash.Value;
- }
-
- public override bool Equals(object obj) {
- NewTypeInfo other = obj as NewTypeInfo;
- if (other == null) return false;
-
-
- if (_baseType.Equals(other._baseType) &&
- _interfaceTypes.Count == other._interfaceTypes.Count) {
-
- for (int i = 0; i < _interfaceTypes.Count; i++) {
- if (!_interfaceTypes[i].Equals(other._interfaceTypes[i])) return false;
- }
- return true;
- }
- return false;
- }
- }
- }