TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType) { TypeSpec spec; if (import_cache.TryGetValue (type, out spec)) { if (spec.BuiltinType == BuiltinTypeSpec.Type.Object) { if (dtype.IsDynamicObject (this)) return module.Compiler.BuiltinTypes.Dynamic; return spec; } if (!spec.IsGeneric || type.IsGenericTypeDefinition) return spec; if (!dtype.HasDynamicAttribute (this)) return spec; // We've found same object in the cache but this one has a dynamic custom attribute // and it's most likely dynamic version of same type IFoo<object> agains IFoo<dynamic> // Do type resolve process again in that case // TODO: Handle cases where they still unify } if (IsMissingType (type)) { spec = new TypeSpec (MemberKind.MissingType, declaringType, new ImportedTypeDefinition (type, this), type, Modifiers.PUBLIC); spec.MemberCache = MemberCache.Empty; import_cache.Add (type, spec); return spec; } if (type.IsGenericType && !type.IsGenericTypeDefinition) { var type_def = type.GetGenericTypeDefinition (); // Generic type definition can also be forwarded if (compiled_types.TryGetValue (type_def, out spec)) return spec; var targs = CreateGenericArguments (0, type.GetGenericArguments (), dtype); if (declaringType == null) { // Simple case, no nesting spec = CreateType (type_def, null, new DynamicTypeReader (), canImportBaseType); spec = spec.MakeGenericType (module, targs); } else { // // Nested type case, converting .NET types like // A`1.B`1.C`1<int, long, string> to typespec like // A<int>.B<long>.C<string> // var nested_hierarchy = new List<TypeSpec> (); while (declaringType.IsNested) { nested_hierarchy.Add (declaringType); declaringType = declaringType.DeclaringType; } int targs_pos = 0; if (declaringType.Arity > 0) { spec = declaringType.MakeGenericType (module, targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ()); targs_pos = spec.Arity; } else { spec = declaringType; } for (int i = nested_hierarchy.Count; i != 0; --i) { var t = nested_hierarchy [i - 1]; spec = MemberCache.FindNestedType (spec, t.Name, t.Arity); if (t.Arity > 0) { spec = spec.MakeGenericType (module, targs.Skip (targs_pos).Take (spec.Arity).ToArray ()); targs_pos += t.Arity; } } string name = type.Name; int index = name.IndexOf ('`'); if (index > 0) name = name.Substring (0, index); spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos); if (spec == null) return null; if (spec.Arity > 0) { spec = spec.MakeGenericType (module, targs.Skip (targs_pos).ToArray ()); } } // Don't add generic type with dynamic arguments, they can interfere with same type // using object type arguments if (!spec.HasDynamicElement) { // Add to reading cache to speed up reading if (!import_cache.ContainsKey (type)) import_cache.Add (type, spec); } return spec; } Modifiers mod; MemberKind kind; var ma = type.Attributes; switch (ma & TypeAttributes.VisibilityMask) { case TypeAttributes.Public: case TypeAttributes.NestedPublic: mod = Modifiers.PUBLIC; break; case TypeAttributes.NestedPrivate: mod = Modifiers.PRIVATE; break; case TypeAttributes.NestedFamily: mod = Modifiers.PROTECTED; break; case TypeAttributes.NestedFamORAssem: mod = Modifiers.PROTECTED | Modifiers.INTERNAL; break; default: mod = Modifiers.INTERNAL; break; } if ((ma & TypeAttributes.Interface) != 0) { kind = MemberKind.Interface; } else if (type.IsGenericParameter) { kind = MemberKind.TypeParameter; } else { var base_type = type.BaseType; if (base_type == null || (ma & TypeAttributes.Abstract) != 0) { kind = MemberKind.Class; } else { kind = DetermineKindFromBaseType (base_type); if (kind == MemberKind.Struct || kind == MemberKind.Delegate) { mod |= Modifiers.SEALED; } } if (kind == MemberKind.Class) { if ((ma & TypeAttributes.Sealed) != 0) { mod |= Modifiers.SEALED; if ((ma & TypeAttributes.Abstract) != 0) mod |= Modifiers.STATIC; } else if ((ma & TypeAttributes.Abstract) != 0) { mod |= Modifiers.ABSTRACT; } } } var definition = new ImportedTypeDefinition (type, this); TypeSpec pt; if (kind == MemberKind.Enum) { const BindingFlags underlying_member = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var type_members = type.GetFields (underlying_member); foreach (var type_member in type_members) { spec = new EnumSpec (declaringType, definition, CreateType (type_member.FieldType), type, mod); break; } if (spec == null) kind = MemberKind.Class; } else if (kind == MemberKind.TypeParameter) { spec = CreateTypeParameter (type, declaringType); } else if (type.IsGenericTypeDefinition) { definition.TypeParameters = CreateGenericParameters (type, declaringType); } else if (compiled_types.TryGetValue (type, out pt)) { // // Same type was found in inside compiled types. It's // either build-in type or forward referenced typed // which point into just compiled assembly. // spec = pt; BuiltinTypeSpec bts = pt as BuiltinTypeSpec; if (bts != null) bts.SetDefinition (definition, type, mod); } if (spec == null) spec = new TypeSpec (kind, declaringType, definition, type, mod); import_cache.Add (type, spec); if (kind == MemberKind.TypeParameter) { if (canImportBaseType) ImportTypeParameterTypeConstraints ((TypeParameterSpec) spec, type); return spec; } // // Two stage setup as the base type can be inflated declaring type or // another nested type inside same declaring type which has not been // loaded, therefore we can import a base type of nested types once // the types have been imported // if (canImportBaseType) ImportTypeBase (spec, type); return spec; }
public TypeSpec CreateType (Type type, TypeSpec declaringType, ICustomAttributeProvider ca, int dynamicCursor, bool canImportBaseType) { TypeSpec spec; if (import_cache.TryGetValue (type, out spec)) { if (ca == null) return spec; if (type == typeof (object)) { if (IsDynamicType (ca, dynamicCursor)) return InternalType.Dynamic; return spec; } if (!spec.IsGeneric) return spec; #if NET_4_0 if (!ca.IsDefined (typeof (DynamicAttribute), false)) #endif return spec; // We've found same object in the cache but this one has a dynamic custom attribute // and it's most likely dynamic version of same type IFoo<object> agains IFoo<dynamic> // Do resolve the type process again in that case } if (type.IsGenericType && !type.IsGenericTypeDefinition) { var type_def = type.GetGenericTypeDefinition (); var targs = CreateGenericArguments (0, type.GetGenericArguments (), ca, dynamicCursor + 1); if (declaringType == null) { // Simple case, no nesting spec = CreateType (type_def, null, null, 0, canImportBaseType); spec = spec.MakeGenericType (targs); } else { // // Nested type case, converting .NET types like // A`1.B`1.C`1<int, long, string> to typespec like // A<int>.B<long>.C<string> // var nested_hierarchy = new List<TypeSpec> (); while (declaringType.IsNested) { nested_hierarchy.Add (declaringType); declaringType = declaringType.DeclaringType; } int targs_pos = 0; if (declaringType.Arity > 0) { spec = declaringType.MakeGenericType (targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ()); targs_pos = spec.Arity; } else { spec = declaringType; } for (int i = nested_hierarchy.Count; i != 0; --i) { var t = nested_hierarchy [i - 1]; spec = MemberCache.FindNestedType (spec, t.Name, t.Arity); if (t.Arity > 0) { spec = spec.MakeGenericType (targs.Skip (targs_pos).Take (spec.Arity).ToArray ()); targs_pos += t.Arity; } } string name = type.Name; int index = name.IndexOf ('`'); if (index > 0) name = name.Substring (0, index); spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos); if (spec.Arity > 0) { spec = spec.MakeGenericType (targs.Skip (targs_pos).ToArray ()); } } // Don't add generic type with dynamic arguments, they can interfere with same type // using object type arguments if (!spec.HasDynamicElement) { // Add to reading cache to speed up reading if (!import_cache.ContainsKey (type)) import_cache.Add (type, spec); } return spec; } Modifiers mod; MemberKind kind; var ma = type.Attributes; switch (ma & TypeAttributes.VisibilityMask) { case TypeAttributes.Public: case TypeAttributes.NestedPublic: mod = Modifiers.PUBLIC; break; case TypeAttributes.NestedPrivate: mod = Modifiers.PRIVATE; break; case TypeAttributes.NestedFamily: mod = Modifiers.PROTECTED; break; case TypeAttributes.NestedFamORAssem: mod = Modifiers.PROTECTED | Modifiers.INTERNAL; break; default: mod = Modifiers.INTERNAL; break; } if ((ma & TypeAttributes.Interface) != 0) { kind = MemberKind.Interface; } else if (type.IsGenericParameter) { kind = MemberKind.TypeParameter; } else if (type.IsClass || type.IsAbstract) { // System.Reflection: System.Enum returns false for IsClass if ((ma & TypeAttributes.Sealed) != 0 && type.IsSubclassOf (typeof (MulticastDelegate))) { kind = MemberKind.Delegate; mod |= Modifiers.SEALED; } else { kind = MemberKind.Class; if ((ma & TypeAttributes.Sealed) != 0) { mod |= Modifiers.SEALED; if ((ma & TypeAttributes.Abstract) != 0) mod |= Modifiers.STATIC; } else if ((ma & TypeAttributes.Abstract) != 0) { mod |= Modifiers.ABSTRACT; } } } else if (type.IsEnum) { kind = MemberKind.Enum; } else { kind = MemberKind.Struct; mod |= Modifiers.SEALED; } var definition = new ImportedTypeDefinition (this, type); PredefinedTypeSpec pt; if (kind == MemberKind.Enum) { const BindingFlags underlying_member = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var type_members = type.GetFields (underlying_member); foreach (var type_member in type_members) { spec = new EnumSpec (declaringType, definition, CreateType (type_member.FieldType), type, mod); break; } if (spec == null) kind = MemberKind.Class; } else if (kind == MemberKind.TypeParameter) { // Return as type_cache was updated return CreateTypeParameter (type, declaringType); } else if (type.IsGenericTypeDefinition) { definition.TypeParameters = CreateGenericParameters (type, declaringType); // Constraints are not loaded on demand and can reference this type if (import_cache.TryGetValue (type, out spec)) return spec; } else if (type_2_predefined.TryGetValue (type, out pt)) { spec = pt; pt.SetDefinition (definition, type); } if (spec == null) spec = new TypeSpec (kind, declaringType, definition, type, mod); import_cache.Add (type, spec); // // Two stage setup as the base type can be inflated declaring type or // another nested type inside same declaring type which has not been // loaded, therefore we can import a base type of nested types once // the types have been imported // if (canImportBaseType) ImportTypeBase (spec, type); return spec; }