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; }
TypeSpec CreateType (MetaType type, DynamicTypeReader dtype, bool canImportBaseType) { TypeSpec declaring_type; if (type.IsNested && !type.IsGenericParameter) declaring_type = CreateType (type.DeclaringType, new DynamicTypeReader (type.DeclaringType), true); else declaring_type = null; return CreateType (type, declaring_type, dtype, canImportBaseType); }
TypeSpec ImportType (MetaType type, DynamicTypeReader dtype) { if (type.HasElementType) { var element = type.GetElementType (); ++dtype.Position; var spec = ImportType (element, dtype); if (type.IsArray) return ArrayContainer.MakeType (module, spec, type.GetArrayRank ()); if (type.IsByRef) return ReferenceContainer.MakeType (module, spec); if (type.IsPointer) return PointerContainer.MakeType (module, spec); throw new NotImplementedException ("Unknown element type " + type.ToString ()); } return CreateType (type, dtype, true); }
TypeSpec[] CreateGenericArguments (int first, MetaType[] tparams, DynamicTypeReader dtype) { ++dtype.Position; var tspec = new TypeSpec [tparams.Length - first]; for (int pos = first; pos < tparams.Length; ++pos) { var type = tparams[pos]; int index = pos - first; TypeSpec spec; if (type.HasElementType) { var element = type.GetElementType (); ++dtype.Position; spec = ImportType (element, dtype); if (!type.IsArray) { throw new NotImplementedException ("Unknown element type " + type.ToString ()); } spec = ArrayContainer.MakeType (module, spec, type.GetArrayRank ()); } else { spec = CreateType (type, dtype, true); // // We treat nested generic types as inflated internally where // reflection uses type definition // // class A<T> { // IFoo<A<T>> foo; // A<T> is definition in this case // } // // TODO: Is full logic from CreateType needed here as well? // if (!IsMissingType (type) && type.IsGenericTypeDefinition) { var targs = CreateGenericArguments (0, type.GetGenericArguments (), dtype); spec = spec.MakeGenericType (module, targs); } } ++dtype.Position; tspec[index] = spec; } return tspec; }
TypeSpec ImportType (MetaType type, DynamicTypeReader dtype) { if (type.HasElementType) { var element = type.GetElementType (); ++dtype.Position; var spec = ImportType (element, dtype); if (type.IsArray) return ArrayContainer.MakeType (module, spec, type.GetArrayRank ()); if (type.IsByRef) return ReferenceContainer.MakeType (module, spec); if (type.IsPointer) return PointerContainer.MakeType (module, spec); throw new NotImplementedException ("Unknown element type " + type.ToString ()); } TypeSpec compiled_type; if (compiled_types.TryGetValue (type, out compiled_type)) { if (compiled_type.BuiltinType == BuiltinTypeSpec.Type.Object && dtype.IsDynamicObject ()) return module.Compiler.BuiltinTypes.Dynamic; return compiled_type; } return CreateType (type, dtype, true); }