[652390] Return type inference can inflate using type parameters out of the reach
[mono.git] / mcs / mcs / import.cs
index 2adc4d63c29d9b331089e1a743675a0518c1efc1..7633c7dbd42a5c713a102272dc94a830a76fee5e 100644 (file)
@@ -18,15 +18,25 @@ using System.Runtime.InteropServices;
 
 namespace Mono.CSharp
 {
-       public static class Import
+       public class ReflectionMetaImporter
        {
-               static Dictionary<Type, TypeSpec> import_cache;
-               static Dictionary<Type, PredefinedTypeSpec> type_2_predefined;
+               Dictionary<Type, TypeSpec> import_cache;
+               Dictionary<Type, PredefinedTypeSpec> type_2_predefined;
 
-               public static void Initialize ()
+               public ReflectionMetaImporter ()
                {
                        import_cache = new Dictionary<Type, TypeSpec> (1024, ReferenceEquality<Type>.Default);
+                       IgnorePrivateMembers = true;
+               }
+
+               #region Properties
+
+               public bool IgnorePrivateMembers { get; set; }
 
+               #endregion
+
+               public void Initialize ()
+               {
                        // Setup mapping for predefined types
                        type_2_predefined = new Dictionary<Type, PredefinedTypeSpec> () {
                                { typeof (object), TypeManager.object_type },
@@ -67,7 +77,7 @@ namespace Mono.CSharp
                        };
                }
 
-               public static FieldSpec CreateField (FieldInfo fi, TypeSpec declaringType)
+               public FieldSpec CreateField (FieldInfo fi, TypeSpec declaringType)
                {
                        Modifiers mod = 0;
                        var fa = fi.Attributes;
@@ -85,26 +95,36 @@ namespace Mono.CSharp
                                        mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
                                        break;
                                default:
+                                       // Ignore private fields (even for error reporting) to not require extra dependencies
+                                       if (IgnorePrivateMembers || fi.IsDefined (typeof (CompilerGeneratedAttribute), false))
+                                               return null;
+
                                        mod = Modifiers.PRIVATE;
                                        break;
                        }
 
-                       // Ignore private fields (even for error reporting) to not require extra dependencies
-                       if (mod == Modifiers.PRIVATE)
-                               return null;
-
                        var definition = new ImportedMemberDefinition (fi);
+                       TypeSpec field_type;
+
+                       try {
+                               field_type = ImportType (fi.FieldType, fi, 0);
+                       } catch (Exception e) {
+                               // TODO: I should construct fake TypeSpec based on TypeRef signature
+                               // but there is no way to do it with System.Reflection
+                               throw new InternalErrorException (e, "Cannot import field `{0}.{1}' referenced in assembly `{2}'",
+                                       declaringType.GetSignatureForError (), fi.Name, declaringType.Assembly);
+                       }
 
                        if ((fa & FieldAttributes.Literal) != 0) {
-                               var     c = Constant.CreateConstantFromValue (ImportType (fi.FieldType), fi.GetValue (fi), Location.Null);
-                               return new ConstSpec (declaringType, definition, ImportType (fi.FieldType), fi, mod, c);
+                               var c = Constant.CreateConstantFromValue (field_type, fi.GetValue (fi), Location.Null);
+                               return new ConstSpec (declaringType, definition, field_type, fi, mod, c);
                        }
 
                        if ((fa & FieldAttributes.InitOnly) != 0) {
-                               if (fi.FieldType == typeof (decimal)) {
+                               if (field_type == TypeManager.decimal_type) {
                                        var dc = ReadDecimalConstant (fi);
                                        if (dc != null)
-                                               return new ConstSpec (declaringType, definition, ImportType (fi.FieldType), fi, mod, dc);
+                                               return new ConstSpec (declaringType, definition, field_type, fi, mod, dc);
                                }
 
                                mod |= Modifiers.READONLY;
@@ -123,17 +143,17 @@ namespace Mono.CSharp
                        if ((fa & FieldAttributes.Static) != 0)
                                mod |= Modifiers.STATIC;
 
-                       if (fi.FieldType.IsValueType) {
+                       if (field_type.IsStruct) {
                                 if (fi.IsDefined (typeof (FixedBufferAttribute), false)) {
                                        var element_field = CreateField (fi.FieldType.GetField (FixedField.FixedElementName), declaringType);
                                        return new FixedFieldSpec (declaringType, definition, fi, element_field, mod);
                                }
                        }
 
-                       return new FieldSpec (declaringType, definition, ImportType (fi.FieldType), fi, mod);
+                       return new FieldSpec (declaringType, definition, field_type, fi, mod);
                }
 
-               public static EventSpec CreateEvent (EventInfo ei, TypeSpec declaringType, MethodSpec add, MethodSpec remove)
+               public EventSpec CreateEvent (EventInfo ei, TypeSpec declaringType, MethodSpec add, MethodSpec remove)
                {
                        add.IsAccessor = true;
                        remove.IsAccessor = true;
@@ -142,10 +162,10 @@ namespace Mono.CSharp
                                throw new NotImplementedException ("Different accessor modifiers " + ei.Name);
 
                        var definition = new ImportedMemberDefinition (ei);
-                       return new EventSpec (declaringType, definition, ImportType (ei.EventHandlerType), add.Modifiers, add, remove);
+                       return new EventSpec (declaringType, definition, ImportType (ei.EventHandlerType, ei, 0), add.Modifiers, add, remove);
                }
 
-               static T[] CreateGenericParameters<T> (Type type, TypeSpec declaringType) where T : TypeSpec
+               T[] CreateGenericParameters<T> (Type type, TypeSpec declaringType) where T : TypeSpec
                {
                        Type[] tparams = type.GetGenericArguments ();
 
@@ -182,54 +202,51 @@ namespace Mono.CSharp
                        if (tparams.Length - parent_owned_count == 0)
                                return null;
 
-                       return CreateGenericParameters<T> (parent_owned_count, tparams);
+                       return CreateGenericParameters<T> (parent_owned_count, tparams, null, 0);
                }
 
-               static T[] CreateGenericParameters<T> (int first, Type[] tparams) where T : TypeSpec
+               T[] CreateGenericParameters<T> (int first, Type[] tparams, ICustomAttributeProvider ca, int dynamicCursor) where T : TypeSpec
                {
                        var tspec = new T [tparams.Length - first];
                        for (int pos = first; pos < tparams.Length; ++pos) {
                                var type = tparams[pos];
+                               int index = pos - first;
+
                                if (type.HasElementType) {
                                        var element = type.GetElementType ();
-                                       var spec = CreateType (element);
+                                       var spec = ImportType (element);
 
                                        if (type.IsArray) {
-                                               tspec[pos - first] = (T) (TypeSpec) ArrayContainer.MakeType (spec, type.GetArrayRank ());
+                                               tspec[index] = (T) (TypeSpec) ArrayContainer.MakeType (spec, type.GetArrayRank ());
                                                continue;
                                        }
 
                                        throw new NotImplementedException ("Unknown element type " + type.ToString ());
                                }
 
-                               tspec [pos - first] = (T) CreateType (type);
+                               tspec [index] = (T) CreateType (type, ca, dynamicCursor + index + 1, true);
                        }
 
                        return tspec;
                }
 
-               public static MethodSpec CreateMethod (MethodBase mb, TypeSpec declaringType)
+               public MethodSpec CreateMethod (MethodBase mb, TypeSpec declaringType)
                {
                        Modifiers mod = ReadMethodModifiers (mb, declaringType);
-                       //if (declaringType.IsInterface) {
-                       //    mod = (mod & ~Modifiers.ABSTRACT) | Modifiers.VIRTUAL;
-                       //}
-
-                       bool is_generic;
+                       TypeParameterSpec[] tparams;
                        ImportedMethodDefinition definition;
 
-                       var parameters = ParametersImported.Create (declaringType, mb);
+                       var parameters = CreateParameters (declaringType, mb.GetParameters (), mb);
 
                        if (mb.IsGenericMethod) {
                                if (!mb.IsGenericMethodDefinition)
                                        throw new NotSupportedException ("assert");
 
-                               var tparams = CreateGenericParameters<TypeParameterSpec>(0, mb.GetGenericArguments ());
+                               tparams = CreateGenericParameters<TypeParameterSpec>(0, mb.GetGenericArguments (), null, 0);
                                definition = new ImportedGenericMethodDefinition ((MethodInfo) mb, parameters, tparams);
-                               is_generic = true;
                        } else {
                                definition = new ImportedMethodDefinition (mb, parameters);
-                               is_generic = false;
+                               tparams = null;
                        }
 
                        MemberKind kind;
@@ -243,36 +260,129 @@ namespace Mono.CSharp
                                //
                                string name = mb.Name;
                                kind = MemberKind.Method;
-                               if (!mb.DeclaringType.IsInterface && name.Length > 6) {
+                               if (tparams == null && !mb.DeclaringType.IsInterface && name.Length > 6) {
                                        if ((mod & (Modifiers.STATIC | Modifiers.PUBLIC)) == (Modifiers.STATIC | Modifiers.PUBLIC)) {
                                                if (name[2] == '_' && name[1] == 'p' && name[0] == 'o') {
                                                        var op_type = Operator.GetType (name);
-                                                       if (op_type.HasValue) {
+                                                       if (op_type.HasValue && parameters.Count > 0 && parameters.Count < 3) {
                                                                kind = MemberKind.Operator;
                                                        }
                                                }
                                        } else if (parameters.IsEmpty && name == Destructor.MetadataName) {
                                                kind = MemberKind.Destructor;
+                                               if (declaringType == TypeManager.object_type) {
+                                                       mod &= ~Modifiers.OVERRIDE;
+                                                       mod |= Modifiers.VIRTUAL;
+                                               }
                                        }
                                }
 
-                               returnType = ImportType (((MethodInfo)mb).ReturnType);
+                               var mi = (MethodInfo) mb;
+                               returnType = ImportType (mi.ReturnType, mi.ReturnTypeCustomAttributes, 0);
+
+                               // Cannot set to OVERRIDE without full hierarchy checks
+                               // this flag indicates that the method could be override
+                               // but further validation is needed
+                               if ((mod & Modifiers.OVERRIDE) != 0 && kind == MemberKind.Method && declaringType.BaseType != null) {
+                                       var filter = MemberFilter.Method (name, tparams != null ? tparams.Length : 0, parameters, null);
+                                       var candidate = MemberCache.FindMember (declaringType.BaseType, filter, BindingRestriction.None);
+
+                                       //
+                                       // For imported class method do additional validation to be sure that metadata
+                                       // override flag was correct
+                                       // 
+                                       // Difference between protected internal and protected is ok
+                                       //
+                                       const Modifiers conflict_mask = Modifiers.AccessibilityMask & ~Modifiers.INTERNAL;
+                                       if (candidate == null || (candidate.Modifiers & conflict_mask) != (mod & conflict_mask) || candidate.IsStatic) {
+                                               mod &= ~Modifiers.OVERRIDE;
+                                       }
+                               }
                        }
 
                        MethodSpec ms = new MethodSpec (kind, declaringType, definition, returnType, mb, parameters, mod);
-                       if (is_generic)
+                       if (tparams != null)
                                ms.IsGeneric = true;
 
                        return ms;
                }
 
                //
-               // Returns null when the property is not valid C# property
+               // Imports System.Reflection parameters
                //
-               public static PropertySpec CreateProperty (PropertyInfo pi, TypeSpec declaringType, MethodSpec get, MethodSpec set)
+               AParametersCollection CreateParameters (TypeSpec parent, ParameterInfo[] pi, MethodBase method)
                {
-                       var definition = new ImportedMemberDefinition (pi);
+                       int varargs = method != null && (method.CallingConvention & CallingConventions.VarArgs) != 0 ? 1 : 0;
+
+                       if (pi.Length == 0 && varargs == 0)
+                               return ParametersCompiled.EmptyReadOnlyParameters;
+
+                       TypeSpec[] types = new TypeSpec[pi.Length + varargs];
+                       IParameterData[] par = new IParameterData[pi.Length + varargs];
+                       bool is_params = false;
+                       for (int i = 0; i < pi.Length; i++) {
+                               ParameterInfo p = pi[i];
+                               Parameter.Modifier mod = 0;
+                               Expression default_value = null;
+                               if (p.ParameterType.IsByRef) {
+                                       if ((p.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out)
+                                               mod = Parameter.Modifier.OUT;
+                                       else
+                                               mod = Parameter.Modifier.REF;
+
+                                       //
+                                       // Strip reference wrapping
+                                       //
+                                       var el = p.ParameterType.GetElementType ();
+                                       types[i] = ImportType (el, p, 0);       // TODO: 1 to be csc compatible
+                               } else if (i == 0 && method.IsStatic && parent.IsStatic && // TODO: parent.Assembly.IsExtension &&
+                                       HasExtensionAttribute (CustomAttributeData.GetCustomAttributes (method)) != null) {
+                                       mod = Parameter.Modifier.This;
+                                       types[i] = ImportType (p.ParameterType);
+                               } else {
+                                       types[i] = ImportType (p.ParameterType, p, 0);
+
+                                       if (i >= pi.Length - 2 && types[i] is ArrayContainer) {
+                                               var cattrs = CustomAttributeData.GetCustomAttributes (p);
+                                               if (cattrs != null && cattrs.Any (l => l.Constructor.DeclaringType == typeof (ParamArrayAttribute))) {
+                                                       mod = Parameter.Modifier.PARAMS;
+                                                       is_params = true;
+                                               }
+                                       }
 
+                                       if (!is_params && p.IsOptional) {
+                                               object value = p.DefaultValue;
+                                               var ptype = types[i];
+                                               if (((p.Attributes & ParameterAttributes.HasDefault) != 0 && ptype.Kind != MemberKind.TypeParameter) || p.IsDefined (typeof (DecimalConstantAttribute), false)) {
+                                                       var dtype = value == null ? ptype : ImportType (value.GetType ());
+                                                       default_value = Constant.CreateConstant (null, dtype, value, Location.Null);
+                                               } else if (value == Missing.Value) {
+                                                       default_value = EmptyExpression.MissingValue;
+                                               } else {
+                                                       default_value = new DefaultValueExpression (new TypeExpression (ptype, Location.Null), Location.Null);
+                                               }
+                                       }
+                               }
+
+                               par[i] = new ParameterData (p.Name, mod, default_value);
+                       }
+
+                       if (varargs != 0) {
+                               par[par.Length - 1] = new ArglistParameter (Location.Null);
+                               types[types.Length - 1] = InternalType.Arglist;
+                       }
+
+                       return method != null ?
+                               new ParametersImported (par, types, varargs != 0, is_params) :
+                               new ParametersImported (par, types, is_params);
+               }
+
+
+               //
+               // Returns null when the property is not valid C# property
+               //
+               public PropertySpec CreateProperty (PropertyInfo pi, TypeSpec declaringType, MethodSpec get, MethodSpec set)
+               {
                        Modifiers mod = 0;
                        AParametersCollection param = null;
                        TypeSpec type = null;
@@ -288,22 +398,32 @@ namespace Mono.CSharp
                                        is_valid_property = false;
 
                                var set_param_count = set.Parameters.Count - 1;
-                               if (set_param_count < 0)
-                                       is_valid_property = false;
 
-                               var data = new IParameterData [set_param_count];
-                               var types = new TypeSpec[set_param_count];
-                               for (int i = 0; i < set_param_count; ++i ) {
-                                       data[i] = set.Parameters.FixedParameters[i];
-                                       types[i] = set.Parameters.Types[i];
+                               if (set_param_count < 0) {
+                                       set_param_count = 0;
+                                       is_valid_property = false;
                                }
 
-                               var set_param = new ParametersImported (data, types);
                                var set_type = set.Parameters.Types[set_param_count];
 
                                if (mod == 0) {
+                                       AParametersCollection set_based_param;
+
+                                       if (set_param_count == 0) {
+                                               set_based_param = ParametersCompiled.EmptyReadOnlyParameters;
+                                       } else {
+                                               //
+                                               // Create indexer parameters based on setter method parameters (the last parameter has to be removed)
+                                               //
+                                               var data = new IParameterData[set_param_count];
+                                               var types = new TypeSpec[set_param_count];
+                                               Array.Copy (set.Parameters.FixedParameters, data, set_param_count);
+                                               Array.Copy (set.Parameters.Types, types, set_param_count);
+                                               set_based_param = new ParametersImported (data, types, set.Parameters.HasParams);
+                                       }
+
                                        mod = set.Modifiers;
-                                       param = set_param;
+                                       param = set_based_param;
                                        type = set_type;
                                } else {
                                        if (set_param_count != get.Parameters.Count)
@@ -313,7 +433,7 @@ namespace Mono.CSharp
                                                is_valid_property = false;
 
                                        // Possible custom accessor modifiers
-                                       if ((mod & ~Modifiers.AccessibilityMask) != (set.Modifiers & ~Modifiers.AccessibilityMask)) {
+                                       if ((mod & Modifiers.AccessibilityMask) != (set.Modifiers & Modifiers.AccessibilityMask)) {
                                                var get_acc = mod & Modifiers.AccessibilityMask;
                                                if (get_acc != Modifiers.PUBLIC) {
                                                        var set_acc = set.Modifiers & Modifiers.AccessibilityMask;
@@ -325,7 +445,7 @@ namespace Mono.CSharp
                                                                        is_valid_property = false; // Neither is more restrictive
                                                                }
 
-                                                               if (set_restr) {
+                                                               if (get_restr) {
                                                                        mod &= ~Modifiers.AccessibilityMask;
                                                                        mod |= set_acc;
                                                                }
@@ -356,11 +476,11 @@ namespace Mono.CSharp
                                }
 
                                if (is_valid_property)
-                                       spec = new IndexerSpec (declaringType, definition, type, param, pi, mod);
+                                       spec = new IndexerSpec (declaringType, new ImportedIndexerDefinition (pi, param), type, param, pi, mod);
                        }
 
                        if (spec == null)
-                               spec = new PropertySpec (MemberKind.Property, declaringType, definition, type, pi, mod);
+                               spec = new PropertySpec (MemberKind.Property, declaringType, new ImportedMemberDefinition (pi), type, pi, mod);
 
                        if (!is_valid_property) {
                                spec.IsNotRealProperty = true;
@@ -375,39 +495,106 @@ namespace Mono.CSharp
                        return spec;
                }
 
-               public static TypeSpec CreateType (Type type)
+               public TypeSpec CreateType (Type type)
                {
-                       return CreateType (type, null);
+                       return CreateType (type, null, 0, true);
                }
 
-               public static TypeSpec CreateType (Type type, TypeSpec declaringType)
+               TypeSpec CreateType (Type type, ICustomAttributeProvider ca, int dynamicCursor, bool canImportBaseType)
+               {
+                       TypeSpec declaring_type;
+                       if (type.IsNested && !type.IsGenericParameter)
+                               declaring_type = CreateType (type.DeclaringType, type.DeclaringType, 0, true);
+                       else
+                               declaring_type = null;
+
+                       return CreateType (type, declaring_type, ca, dynamicCursor, canImportBaseType);
+               }
+
+               public TypeSpec CreateType (Type type, TypeSpec declaringType, ICustomAttributeProvider ca, int dynamicCursor, bool canImportBaseType)
                {
                        TypeSpec spec;
-                       if (import_cache.TryGetValue (type, out spec))
-                               return 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 ();
-                               spec = CreateType (type_def, declaringType);
+                               var targs = CreateGenericParameters<TypeSpec> (0, type.GetGenericArguments (), ca, dynamicCursor);
+                               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;
+                                       }
 
-                               var targs = CreateGenericParameters<TypeSpec> (type, null);
+                                       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;
+                                       }
 
-                               InflatedTypeSpec inflated;
-                               if (targs == null) {
-                                       // Inflating nested non-generic type, same in TypeSpec::InflateMember
-                                       inflated = new InflatedTypeSpec (spec, declaringType, TypeSpec.EmptyTypes);
-                               } else {
-                                       // CreateGenericParameters constraint could inflate type
-                                       if (import_cache.ContainsKey (type))
-                                               return import_cache[type];
+                                       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;
+                                               }
+                                       }
 
-                                       inflated = spec.MakeGenericType (targs);
+                                       string name = type.Name;
+                                       int index = name.IndexOf ('`');
+                                       if (index > 0)
+                                               name = name.Substring (0, index);
 
-                                       // Use of reading cache to speed up reading only
-                                       import_cache.Add (type, inflated);
+                                       spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos);
+                                       if (spec.Arity > 0) {
+                                               spec = spec.MakeGenericType (targs.Skip (targs_pos).ToArray ());
+                                       }
                                }
 
-                               return inflated;
+                               // 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;
@@ -437,20 +624,12 @@ namespace Mono.CSharp
                                kind = MemberKind.Interface;
                        } else if (type.IsGenericParameter) {
                                kind = MemberKind.TypeParameter;
-                       } else if (type.IsClass || type.IsAbstract) {                           // SRE: System.Enum returns false for IsClass
+                       } 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 (type == typeof (object)) {
-#if NET_4_0
-                                               var pa = PredefinedAttributes.Get.Dynamic.Type;
-                                               if (pa != null && type.IsDefined (typeof (DynamicAttribute), false))
-                                                       return InternalType.Dynamic;
-#endif
-                                       }
-
                                        if ((ma & TypeAttributes.Sealed) != 0) {
                                                mod |= Modifiers.SEALED;
                                                if ((ma & TypeAttributes.Abstract) != 0)
@@ -466,7 +645,7 @@ namespace Mono.CSharp
                                mod |= Modifiers.SEALED;
                        }
 
-                       var definition = new ImportedTypeDefinition (type);
+                       var definition = new ImportedTypeDefinition (this, type);
                        PredefinedTypeSpec pt;
 
                        if (kind == MemberKind.Enum) {
@@ -476,7 +655,7 @@ namespace Mono.CSharp
 
                                var type_members = type.GetFields (underlying_member);
                                foreach (var type_member in type_members) {
-                                       spec = new EnumSpec (declaringType, definition, Import.CreateType (type_member.FieldType), type, mod);
+                                       spec = new EnumSpec (declaringType, definition, CreateType (type_member.FieldType), type, mod);
                                        break;
                                }
 
@@ -503,22 +682,45 @@ namespace Mono.CSharp
 
                        import_cache.Add (type, spec);
 
-                       if (kind == MemberKind.Interface)
+                       //
+                       // 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 void ImportTypeBase (Type type)
+               {
+                       TypeSpec spec = import_cache[type];
+                       if (spec != null)
+                               ImportTypeBase (spec, type);
+               }
+
+               void ImportTypeBase (TypeSpec spec, Type type)
+               {
+                       if (spec.Kind == MemberKind.Interface)
                                spec.BaseType = TypeManager.object_type;
-                       else if (type.BaseType != null)
-                               spec.BaseType = CreateType (type.BaseType);
+                       else if (type.BaseType != null) {
+                               if (type.BaseType.IsGenericType)
+                                       spec.BaseType = CreateType (type.BaseType, type, 0, true);
+                               else
+                                       spec.BaseType = CreateType (type.BaseType);
+                       }
 
                        var ifaces = type.GetInterfaces ();
                        if (ifaces.Length > 0) {
                                foreach (Type iface in ifaces) {
-                                       spec.AddInterface (Import.CreateType (iface));
+                                       spec.AddInterface (CreateType (iface));
                                }
                        }
-
-                       return spec;
                }
 
-               static TypeParameterSpec CreateTypeParameter (Type type, TypeSpec declaringType)
+               TypeParameterSpec CreateTypeParameter (Type type, TypeSpec declaringType)
                {
                        Variance variance;
                        switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) {
@@ -557,9 +759,13 @@ namespace Mono.CSharp
                        import_cache.Add (type, spec);
 
                        var constraints = type.GetGenericParameterConstraints ();
+                       List<TypeSpec> tparams = null;
                        foreach (var ct in constraints) {
-                               // TODO MemberCache: What to do ??
                                if (ct.IsGenericParameter) {
+                                       if (tparams == null)
+                                               tparams = new List<TypeSpec> ();
+
+                                       tparams.Add (CreateType (ct));
                                        continue;
                                }
 
@@ -579,14 +785,101 @@ namespace Mono.CSharp
                        if (spec.BaseType == null)
                                spec.BaseType = TypeManager.object_type;
 
+                       if (tparams != null)
+                               spec.TypeArguments = tparams.ToArray ();
+
                        return spec;
                }
 
-               public static TypeSpec ImportType (Type type)
+               static Type HasExtensionAttribute (IList<CustomAttributeData> attributes)
+               {
+                       foreach (var attr in attributes) {
+                               var dt = attr.Constructor.DeclaringType;
+                               if (dt.Name == "ExtensionAttribute" && dt.Namespace == "System.Runtime.CompilerServices") {
+                                       return dt;
+                               }
+                       }
+
+                       return null;
+               }
+
+               public void ImportAssembly (Assembly assembly, Namespace targetNamespace)
+               {
+                       Type extension_type = HasExtensionAttribute (CustomAttributeData.GetCustomAttributes (assembly));
+
+                       //
+                       // This part tries to simulate loading of top-level
+                       // types only, any missing dependencies are ignores here.
+                       // Full error report is reported later when the type is
+                       // actually used
+                       //
+                       Type[] all_types;
+                       try {
+                               all_types = assembly.GetTypes ();
+                       } catch (ReflectionTypeLoadException e) {
+                               all_types = e.Types;
+                       }
+
+                       ImportTypes (all_types, targetNamespace, extension_type);
+               }
+
+               public void ImportModule (Module module, Namespace targetNamespace)
+               {
+                       Type extension_type = HasExtensionAttribute (CustomAttributeData.GetCustomAttributes (module));
+
+                       Type[] all_types;
+                       try {
+                               all_types = module.GetTypes ();
+                       } catch (ReflectionTypeLoadException e) {
+                               all_types = e.Types;
+                               throw;
+                       }
+
+                       ImportTypes (all_types, targetNamespace, extension_type);
+               }
+
+               void ImportTypes (Type[] types, Namespace targetNamespace, Type extension_type)
+               {
+                       Namespace ns = targetNamespace;
+                       string prev_namespace = null;
+                       foreach (var t in types) {
+                               if (t == null)
+                                       continue;
+
+                               // Be careful not to trigger full parent type loading
+                               if (t.MemberType == MemberTypes.NestedType)
+                                       continue;
+
+                               if (t.Name[0] == '<')
+                                       continue;
+
+                               var it = CreateType (t, null, t, 0, true);
+                               if (it == null)
+                                       continue;
+
+                               if (prev_namespace != t.Namespace) {
+                                       ns = t.Namespace == null ? targetNamespace : targetNamespace.GetNamespace (t.Namespace, true);
+                                       prev_namespace = t.Namespace;
+                               }
+
+                               ns.AddType (it);
+
+                               if (it.IsStatic && extension_type != null && t.IsDefined (extension_type, false)) {
+                                       it.SetExtensionMethodContainer ();
+                               }
+                       }
+               }
+
+               public TypeSpec ImportType (Type type)
+               {
+                       return ImportType (type, null, 0);
+               }
+
+               public TypeSpec ImportType (Type type, ICustomAttributeProvider ca, int dynamicCursor)
                {
                        if (type.HasElementType) {
                                var element = type.GetElementType ();
-                               var spec = ImportType (element);
+                               var spec = ImportType (element, ca, dynamicCursor + 1);
 
                                if (type.IsArray)
                                        return ArrayContainer.MakeType (spec, type.GetArrayRank ());
@@ -598,13 +891,21 @@ namespace Mono.CSharp
                                throw new NotImplementedException ("Unknown element type " + type.ToString ());
                        }
 
-                       TypeSpec dtype;
-                       if (type.IsNested)
-                               dtype = ImportType (type.DeclaringType);
-                       else
-                               dtype = null;
+                       return CreateType (type, ca, dynamicCursor, true);
+               }
 
-                       return CreateType (type, dtype);
+               static bool IsDynamicType (ICustomAttributeProvider ca, int index)
+               {
+#if NET_4_0
+                       if (ca.IsDefined (typeof (DynamicAttribute), false)) {
+                               if (index == 0)
+                                       return true;
+
+                               var v = (DynamicAttribute) ca.GetCustomAttributes (typeof (DynamicAttribute), false)[0];
+                               return v.TransformFlags[index];
+                       }
+#endif
+                       return false;
                }
 
                //
@@ -612,7 +913,7 @@ namespace Mono.CSharp
                // as IsInitOnly ('readonly' in C# parlance).  We get its value from the 
                // DecimalConstantAttribute metadata.
                //
-               static Constant ReadDecimalConstant (FieldInfo fi)
+               static Constant ReadDecimalConstant (ICustomAttributeProvider fi)
                {
                        object[] attrs = fi.GetCustomAttributes (typeof (DecimalConstantAttribute), false);
                        if (attrs.Length != 1)
@@ -645,21 +946,24 @@ namespace Mono.CSharp
 
                        if ((ma & MethodAttributes.Static) != 0) {
                                mod |= Modifiers.STATIC;
-                       } else if ((ma & MethodAttributes.Final) != 0) {
-                               mod |= Modifiers.SEALED;
-                       } else if ((ma & MethodAttributes.Abstract) != 0 && declaringType.IsClass) {
+                               return mod;
+                       }
+                       if ((ma & MethodAttributes.Abstract) != 0 && declaringType.IsClass) {
                                mod |= Modifiers.ABSTRACT;
+                               return mod;
                        }
 
+                       if ((ma & MethodAttributes.Final) != 0)
+                               mod |= Modifiers.SEALED;
+
                        // It can be sealed and override
                        if ((ma & MethodAttributes.Virtual) != 0) {
-                               if ((ma & MethodAttributes.NewSlot) != 0 || !declaringType.IsClass || mod == Modifiers.PRIVATE) {
-                                       mod |= Modifiers.VIRTUAL;
+                               if ((ma & MethodAttributes.NewSlot) != 0 || !declaringType.IsClass) {
+                                       // No private virtual or sealed virtual
+                                       if ((mod & (Modifiers.PRIVATE | Modifiers.SEALED)) == 0)
+                                               mod |= Modifiers.VIRTUAL;
                                } else {
-                                       // Cannot set to OVERRIDE without full hierarchy checks
-                                       // this flag indicates that the method could be override
-                                       // but further validation is needed
-                                       mod |= Modifiers.OVERRIDE_UNCHECKED;
+                                       mod |= Modifiers.OVERRIDE;
                                }
                        }
 
@@ -684,7 +988,9 @@ namespace Mono.CSharp
                                AttributesBag bag = null;
                                List<string> conditionals = null;
 
-                               var attrs = CustomAttributeData.GetCustomAttributes (mi);
+                               // It should not throw any loading exception
+                               IList<CustomAttributeData> attrs = CustomAttributeData.GetCustomAttributes (mi);
+
                                foreach (var a in attrs) {
                                        var type = a.Constructor.DeclaringType;
                                        if (type == typeof (ObsoleteAttribute)) {
@@ -854,6 +1160,33 @@ namespace Mono.CSharp
                #endregion
        }
 
+       class ImportedIndexerDefinition : ImportedMemberDefinition, IParametersMember
+       {
+               readonly AParametersCollection parameters;
+
+               public ImportedIndexerDefinition (PropertyInfo provider, AParametersCollection parameters)
+                       : base (provider)
+               {
+                       this.parameters = parameters;
+               }
+
+               #region Properties
+
+               public AParametersCollection Parameters {
+                       get {
+                               return parameters;
+                       }
+               }
+
+               public TypeSpec MemberType {
+                       get {
+                               throw new NotImplementedException ();
+                       }
+               }
+
+               #endregion
+       }
+
        class ImportedGenericMethodDefinition : ImportedMethodDefinition, IGenericMethodDefinition
        {
                TypeParameterSpec[] tparams;
@@ -885,10 +1218,12 @@ namespace Mono.CSharp
        {
                TypeParameterSpec[] tparams;
                string name;
+               ReflectionMetaImporter meta_import;
 
-               public ImportedTypeDefinition (Type type)
+               public ImportedTypeDefinition (ReflectionMetaImporter metaImport, Type type)
                        : base (type)
                {
+                       this.meta_import = metaImport;
                }
 
                #region Properties
@@ -935,7 +1270,7 @@ namespace Mono.CSharp
                        if (attr.Length < 1)
                                return null;
 
-                       return Import.CreateType (((CoClassAttribute) attr[0]).CoClass);
+                       return meta_import.CreateType (((CoClassAttribute) attr[0]).CoClass);
                }
 
                public string GetAttributeDefaultMember ()
@@ -954,8 +1289,16 @@ namespace Mono.CSharp
                        return cattrs.AttributeUsage;
                }
 
-               public MemberCache LoadMembers (TypeSpec declaringType)
+               public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
                {
+                       //
+                       // Not interested in members of nested private types unless the importer needs them
+                       //
+                       if (declaringType.IsPrivate && meta_import.IgnorePrivateMembers) {
+                               cache = MemberCache.Empty;
+                               return;
+                       }
+
                        var loading_type = (Type) provider;
                        const BindingFlags all_members = BindingFlags.DeclaredOnly |
                                BindingFlags.Static | BindingFlags.Instance |
@@ -966,13 +1309,10 @@ namespace Mono.CSharp
                                        MethodAttributes.Final;
 
                        Dictionary<MethodBase, MethodSpec> possible_accessors = null;
+                       List<EventSpec> imported_events = null;
+                       EventSpec event_spec;
                        MemberSpec imported;
                        MethodInfo m;
-                       List<string> fields_to_ignore = null;
-
-                       //
-                       // This requires methods to be returned first which seems to work for both Mono and .NET
-                       //
                        MemberInfo[] all;
                        try {
                                all = loading_type.GetMembers (all_members);
@@ -981,114 +1321,158 @@ namespace Mono.CSharp
                                        declaringType.GetSignatureForError (), declaringType.Assembly.Location);
                        }
 
-                       var cache = new MemberCache (all.Length);
-                       foreach (var member in all) {
-                               switch (member.MemberType) {
-                               case MemberTypes.Constructor:
-                               case MemberTypes.Method:
-                                       MethodBase mb = (MethodBase) member;
-
-                                       // Ignore explicitly implemented members
-                                       if ((mb.Attributes & explicit_impl) == explicit_impl && (mb.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private)
-                                               continue;
-
-                                       // Ignore compiler generated methods
-                                       if (mb.IsPrivate && mb.IsDefined (typeof (CompilerGeneratedAttribute), false))
-                                               continue;
-
-                                       imported = Import.CreateMethod (mb, declaringType);
-                                       if (imported.Kind == MemberKind.Method) {
-                                               if (possible_accessors == null)
-                                                       possible_accessors = new Dictionary<MethodBase, MethodSpec> (ReferenceEquality<MethodBase>.Default);
+                       if (cache == null) {
+                               cache = new MemberCache (all.Length);
 
-                                               // There are no metadata rules for accessors, we have to any method as possible candidate
-                                               possible_accessors.Add (mb, (MethodSpec) imported);
-                                       }
-
-                                       break;
-                               case MemberTypes.Property:
-                                       if (possible_accessors == null)
-                                               continue;
-
-                                       var p = (PropertyInfo) member;
-                                       //
-                                       // Links possible accessors with property
-                                       //
-                                       MethodSpec get, set;
-                                       m = p.GetGetMethod (true);
-                                       if (m == null || !possible_accessors.TryGetValue (m, out get))
-                                               get = null;
-
-                                       m = p.GetSetMethod (true);
-                                       if (m == null || !possible_accessors.TryGetValue (m, out set))
-                                               set = null;
-
-                                       // No accessors registered (e.g. explicit implementation)
-                                       if (get == null && set == null)
+                               //
+                               // Do the types first as they can be referenced by the members before
+                               // they are found or inflated
+                               //
+                               foreach (var member in all) {
+                                       if (member.MemberType != MemberTypes.NestedType)
                                                continue;
 
-                                       imported = Import.CreateProperty (p, declaringType, get, set);
-                                       if (imported == null)
-                                               continue;
+                                       Type t = (Type) member;
 
-                                       break;
-                               case MemberTypes.Event:
-                                       if (possible_accessors == null)
+                                       // Ignore compiler generated types, mostly lambda containers
+                                       if (t.IsNotPublic && t.IsDefined (typeof (CompilerGeneratedAttribute), false))
                                                continue;
 
-                                       var e = (EventInfo) member;
-                                       //
-                                       // Links accessors with event
-                                       //
-                                       MethodSpec add, remove;
-                                       m = e.GetAddMethod (true);
-                                       if (m == null || !possible_accessors.TryGetValue (m, out add))
-                                               add = null;
-
-                                       m = e.GetRemoveMethod (true);
-                                       if (m == null || !possible_accessors.TryGetValue (m, out remove))
-                                               remove = null;
+                                       imported = meta_import.CreateType (t, declaringType, t, 0, false);
+                                       cache.AddMember (imported);
+                               }
 
-                                       // Both accessors are required
-                                       if (add == null || remove == null)
+                               foreach (var member in all) {
+                                       if (member.MemberType != MemberTypes.NestedType)
                                                continue;
 
-                                       if (fields_to_ignore == null)
-                                               fields_to_ignore = new List<string> ();
-
-                                       fields_to_ignore.Add (e.Name);
+                                       meta_import.ImportTypeBase ((Type) member);
+                               }
+                       }
 
-                                       imported = Import.CreateEvent (e, declaringType, add, remove);
-                                       break;
-                               case MemberTypes.Field:
-                                       var fi = (FieldInfo) member;
+                       if (!onlyTypes) {
+                               //
+                               // The logic here requires methods to be returned first which seems to work for both Mono and .NET
+                               //
+                               foreach (var member in all) {
+                                       switch (member.MemberType) {
+                                       case MemberTypes.Constructor:
+                                       case MemberTypes.Method:
+                                               MethodBase mb = (MethodBase) member;
+                                               var attrs = mb.Attributes;
+
+                                               if ((attrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Private) {
+                                                       if (meta_import.IgnorePrivateMembers)
+                                                               continue;
+
+                                                       // Ignore explicitly implemented members
+                                                       if ((attrs & explicit_impl) == explicit_impl)
+                                                               continue;
+
+                                                       // Ignore compiler generated methods
+                                                       if (mb.IsDefined (typeof (CompilerGeneratedAttribute), false))
+                                                               continue;
+                                               }
 
-                                       // Ignore compiler generated fields
-                                       if (fi.IsPrivate && fi.IsDefined (typeof (CompilerGeneratedAttribute), false))
-                                               continue;
+                                               imported = meta_import.CreateMethod (mb, declaringType);
+                                               if (imported.Kind == MemberKind.Method && !imported.IsGeneric) {
+                                                       if (possible_accessors == null)
+                                                               possible_accessors = new Dictionary<MethodBase, MethodSpec> (ReferenceEquality<MethodBase>.Default);
 
-                                       if (fields_to_ignore != null && fields_to_ignore.Contains (fi.Name))
-                                               continue;
+                                                       // There are no metadata rules for accessors, we have to consider any method as possible candidate
+                                                       possible_accessors.Add (mb, (MethodSpec) imported);
+                                               }
 
-                                       imported = Import.CreateField (fi, declaringType);
-                                       if (imported == null)
-                                               continue;
+                                               break;
+                                       case MemberTypes.Property:
+                                               if (possible_accessors == null)
+                                                       continue;
+
+                                               var p = (PropertyInfo) member;
+                                               //
+                                               // Links possible accessors with property
+                                               //
+                                               MethodSpec get, set;
+                                               m = p.GetGetMethod (true);
+                                               if (m == null || !possible_accessors.TryGetValue (m, out get))
+                                                       get = null;
+
+                                               m = p.GetSetMethod (true);
+                                               if (m == null || !possible_accessors.TryGetValue (m, out set))
+                                                       set = null;
+
+                                               // No accessors registered (e.g. explicit implementation)
+                                               if (get == null && set == null)
+                                                       continue;
+
+                                               imported = meta_import.CreateProperty (p, declaringType, get, set);
+                                               if (imported == null)
+                                                       continue;
+
+                                               break;
+                                       case MemberTypes.Event:
+                                               if (possible_accessors == null)
+                                                       continue;
+
+                                               var e = (EventInfo) member;
+                                               //
+                                               // Links accessors with event
+                                               //
+                                               MethodSpec add, remove;
+                                               m = e.GetAddMethod (true);
+                                               if (m == null || !possible_accessors.TryGetValue (m, out add))
+                                                       add = null;
+
+                                               m = e.GetRemoveMethod (true);
+                                               if (m == null || !possible_accessors.TryGetValue (m, out remove))
+                                                       remove = null;
+
+                                               // Both accessors are required
+                                               if (add == null || remove == null)
+                                                       continue;
+
+                                               event_spec = meta_import.CreateEvent (e, declaringType, add, remove);
+                                               if (!meta_import.IgnorePrivateMembers) {
+                                                       if (imported_events == null)
+                                                               imported_events = new List<EventSpec> ();
+
+                                                       imported_events.Add (event_spec);
+                                               }
 
-                                       break;
-                               case MemberTypes.NestedType:
-                                       Type t = (Type) member;
+                                               imported = event_spec;
+                                               break;
+                                       case MemberTypes.Field:
+                                               var fi = (FieldInfo) member;
+
+                                               imported = meta_import.CreateField (fi, declaringType);
+                                               if (imported == null)
+                                                       continue;
+
+                                               //
+                                               // For dynamic binder event has to be fully restored to allow operations
+                                               // within the type container to work correctly
+                                               //
+                                               if (imported_events != null) {
+                                                       // The backing event field should be private but it may not
+                                                       int index = imported_events.FindIndex (l => l.Name == fi.Name);
+                                                       if (index >= 0) {
+                                                               event_spec = imported_events[index];
+                                                               event_spec.BackingField = (FieldSpec) imported;
+                                                               imported_events.RemoveAt (index);
+                                                               continue;
+                                                       }
+                                               }
 
-                                       // Ignore compiler generated types, mostly lambda containers
-                                       if (t.IsNotPublic && t.IsDefined (typeof (CompilerGeneratedAttribute), false))
+                                               break;
+                                       case MemberTypes.NestedType:
+                                               // Already in the cache from the first pass
                                                continue;
+                                       default:
+                                               throw new NotImplementedException (member.ToString ());
+                                       }
 
-                                       imported = Import.CreateType (t, declaringType);
-                                       break;
-                               default:
-                                       throw new NotImplementedException (member.ToString ());
+                                       cache.AddMember (imported);
                                }
-
-                               cache.AddMember (imported);
                        }
 
                        if (declaringType.IsInterface && declaringType.Interfaces != null) {
@@ -1096,8 +1480,6 @@ namespace Mono.CSharp
                                        cache.AddInterface (iface);
                                }
                        }
-
-                       return cache;
                }
        }
 
@@ -1145,7 +1527,7 @@ namespace Mono.CSharp
                        throw new NotSupportedException ();
                }
 
-               public MemberCache LoadMembers (TypeSpec declaringType)
+               public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
                {
                        throw new NotImplementedException ();
                }