[Mono.CSharp] Fix bug where overwriting variables cleared the wrong value
[mono.git] / mcs / mcs / class.cs
index ffebadae3722b92d1779a8a0a80457452291dae8..943db46deabceb0b05b664c0a6372b029a967052 100644 (file)
 
 using System;
 using System.Collections.Generic;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Security;
 using System.Security.Permissions;
-using System.Text;
 using System.Linq;
 
 #if NET_2_1
 using XmlElement = System.Object;
-#else
-using System.Xml;
 #endif
 
-using Mono.CompilerServices.SymbolWriter;
+#if STATIC
+using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
+#else
+using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
+using System.Reflection;
+using System.Reflection.Emit;
+#endif
 
 namespace Mono.CSharp {
 
@@ -85,6 +87,10 @@ namespace Mono.CSharp {
                                get { return tc.IsStatic; }
                        }
 
+                       public ModuleContainer Module {
+                               get { return tc.Module; }
+                       }
+
                        public string GetSignatureForError ()
                        {
                                return tc.GetSignatureForError ();
@@ -166,10 +172,12 @@ namespace Mono.CSharp {
                List<MemberCore> operators;
 
                // Holds the compiler generated classes
-               List<CompilerGeneratedClass> compiler_generated;
+               protected List<CompilerGeneratedClass> compiler_generated;
 
                Dictionary<MethodSpec, Method> hoisted_base_call_proxies;
 
+               Dictionary<string, FullNamedExpression> Cache = new Dictionary<string, FullNamedExpression> ();
+
                //
                // Pointers to the default constructor and the default static constructor
                //
@@ -182,7 +190,7 @@ namespace Mono.CSharp {
                // This is an arbitrary choice.  We are interested in looking at _some_ non-static field,
                // and the first one's as good as any.
                //
-               FieldBase first_nonstatic_field = null;
+               FieldBase first_nonstatic_field;
 
                //
                // This one is computed after we can distinguish interfaces
@@ -271,6 +279,18 @@ namespace Mono.CSharp {
                        }
                }
 
+               public virtual AssemblyDefinition DeclaringAssembly {
+                       get {
+                               return Module.DeclaringAssembly;
+                       }
+               }
+
+               IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
+                       get {
+                               return Module.DeclaringAssembly;
+                       }
+               }
+
                public TypeSpec Definition {
                        get {
                                return spec;
@@ -440,8 +460,7 @@ namespace Mono.CSharp {
                public void AddConstructor (Constructor c)
                {
                        bool is_static = (c.ModFlags & Modifiers.STATIC) != 0;
-                       if (!AddToContainer (c, is_static ?
-                               ConstructorBuilder.ConstructorName : ConstructorBuilder.TypeConstructorName))
+                       if (!AddToContainer (c, is_static ? Constructor.ConstructorName : Constructor.TypeConstructorName))
                                return;
                        
                        if (is_static && c.ParameterInfo.IsEmpty){
@@ -635,15 +654,9 @@ namespace Mono.CSharp {
                        }
                }
 
-               public IList<CompilerGeneratedClass> CompilerGeneratedClasses {
-                       get {
-                               return compiler_generated;
-                       }
-               }
-
                protected override TypeAttributes TypeAttr {
                        get {
-                               return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) | base.TypeAttr;
+                               return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel);
                        }
                }
 
@@ -670,7 +683,7 @@ namespace Mono.CSharp {
                                if (OptAttributes == null)
                                        return false;
 
-                               return OptAttributes.Contains (Compiler.PredefinedAttributes.ComImport);
+                               return OptAttributes.Contains (Module.PredefinedAttributes.ComImport);
                        }
                }
 
@@ -784,7 +797,7 @@ namespace Mono.CSharp {
                        if (OptAttributes == null)
                                return null;
 
-                       Attribute a = OptAttributes.Search (Compiler.PredefinedAttributes.CoClass);
+                       Attribute a = OptAttributes.Search (Module.PredefinedAttributes.CoClass);
                        if (a == null)
                                return null;
 
@@ -838,12 +851,14 @@ namespace Mono.CSharp {
                                        continue;
 
                                if (i == 0 && Kind == MemberKind.Class && !fne_resolved.Type.IsInterface) {
-                                       if (fne_resolved.Type == InternalType.Dynamic)
+                                       if (fne_resolved.Type == InternalType.Dynamic) {
                                                Report.Error (1965, Location, "Class `{0}' cannot derive from the dynamic type",
                                                        GetSignatureForError ());
-                                       else
-                                               base_type = fne_resolved.Type;
 
+                                               continue;
+                                       }
+                                       
+                                       base_type = fne_resolved.Type;
                                        base_class = fne_resolved;
                                        continue;
                                }
@@ -1001,19 +1016,19 @@ namespace Mono.CSharp {
                        int type_size = Kind == MemberKind.Struct && first_nonstatic_field == null ? 1 : 0;
 
                        if (IsTopLevel) {
-                               if (Compiler.GlobalRootNamespace.IsNamespace (Name)) {
+                               // TODO: Completely wrong
+                               if (Module.GlobalRootNamespace.IsNamespace (Name)) {
                                        Report.Error (519, Location, "`{0}' clashes with a predefined namespace", Name);
-                                       return false;
                                }
 
-                               ModuleBuilder builder = Module.Compiled.Builder;
-                               TypeBuilder = builder.DefineType (Name, TypeAttr, null, type_size);
+                               TypeBuilder = Module.CreateBuilder (Name, TypeAttr, type_size);
                        } else {
-                               TypeBuilder builder = Parent.TypeBuilder;
-
-                               TypeBuilder = builder.DefineNestedType (Basename, TypeAttr, null, type_size);
+                               TypeBuilder = Parent.TypeBuilder.DefineNestedType (Basename, TypeAttr, null, type_size);
                        }
 
+                       if (DeclaringAssembly.Importer != null)
+                               DeclaringAssembly.Importer.AddCompiledType (TypeBuilder, spec);
+
                        spec.SetMetaInfo (TypeBuilder);
                        spec.MemberCache = new MemberCache (this);
                        spec.DeclaringType = Parent.CurrentType;
@@ -1067,7 +1082,7 @@ namespace Mono.CSharp {
                                var cloned_params = ParametersCompiled.CreateFullyResolved (base_parameters, method.Parameters.Types);
                                if (method.Parameters.HasArglist) {
                                        cloned_params.FixedParameters[0] = new Parameter (null, "__arglist", Parameter.Modifier.NONE, null, Location);
-                                       cloned_params.Types[0] = TypeManager.runtime_argument_handle_type;
+                                       cloned_params.Types[0] = Module.PredefinedTypes.RuntimeArgumentHandle.Resolve (Location);
                                }
 
                                GenericMethod generic_method;
@@ -1137,13 +1152,15 @@ namespace Mono.CSharp {
                                        Report.Error (529, Location,
                                                "Inherited interface `{0}' causes a cycle in the interface hierarchy of `{1}'",
                                            GetSignatureForError (), cycle.GetSignatureForError ());
+
+                                       iface_exprs = null;
                                } else {
                                        Report.Error (146, Location,
                                                "Circular base class dependency involving `{0}' and `{1}'",
                                                GetSignatureForError (), cycle.GetSignatureForError ());
-                               }
 
-                               base_type = null;
+                                       base_type = null;
+                               }
                        }
 
                        if (iface_exprs != null) {
@@ -1205,6 +1222,8 @@ namespace Mono.CSharp {
 
                                // Set base type after type creation
                                TypeBuilder.SetParent (base_type.GetMetaInfo ());
+                       } else {
+                               TypeBuilder.SetParent (null);
                        }
 
                        return true;
@@ -1251,17 +1270,17 @@ namespace Mono.CSharp {
                //
                // Defines the type in the appropriate ModuleBuilder or TypeBuilder.
                //
-               public TypeBuilder CreateType ()
+               public bool CreateType ()
                {
                        if (TypeBuilder != null)
-                               return TypeBuilder;
+                               return !error;
 
                        if (error)
-                               return null;
+                               return false;
 
                        if (!CreateTypeBuilder ()) {
                                error = true;
-                               return null;
+                               return false;
                        }
 
                        if (partial_parts != null) {
@@ -1274,36 +1293,31 @@ namespace Mono.CSharp {
 
                        if (Types != null) {
                                foreach (TypeContainer tc in Types) {
-                                       if (tc.CreateType () == null) {
-                                               error = true;
-                                               return null;
-                                       }
+                                       tc.CreateType ();
                                }
                        }
 
-                       return TypeBuilder;
+                       return true;
                }
 
-               public override TypeBuilder DefineType ()
+               public override void DefineType ()
                {
                        if (error)
-                               return null;
+                               return;
                        if (type_defined)
-                               return TypeBuilder;
+                               return;
 
                        type_defined = true;
 
                        if (!DefineBaseTypes ()) {
                                error = true;
-                               return null;
+                               return;
                        }
 
                        if (!DefineNestedTypes ()) {
                                error = true;
-                               return null;
+                               return;
                        }
-
-                       return TypeBuilder;
                }
 
                public override void SetParameterInfo (List<Constraints> constraints_list)
@@ -1335,9 +1349,22 @@ namespace Mono.CSharp {
                // Replaces normal spec with predefined one when compiling corlib
                // and this type container defines predefined type
                //
-               public void SetPredefinedSpec (PredefinedTypeSpec spec)
-               {
+               public void SetPredefinedSpec (BuildinTypeSpec spec)
+               {
+                       // When compiling build-in types we start with two
+                       // version of same type. One is of BuildinTypeSpec and
+                       // second one is ordinary TypeSpec. The unification
+                       // happens at later stage when we know which type
+                       // really matches the buildin type signature. However
+                       // that means TypeSpec create during CreateType of this
+                       // type has to be replaced with buildin one
+                       // 
+                       spec.SetMetaInfo (TypeBuilder);
+                       spec.MemberCache = this.spec.MemberCache;
+                       spec.DeclaringType = this.spec.DeclaringType;
+
                        this.spec = spec;
+                       current_type = null;
                }
 
                void UpdateTypeParameterConstraints (TypeContainer part)
@@ -1402,8 +1429,7 @@ namespace Mono.CSharp {
                {
                        if (Types != null) {
                                foreach (TypeContainer tc in Types)
-                                       if (tc.DefineType () == null)
-                                               return false;
+                                       tc.DefineType ();
                        }
 
                        return true;
@@ -1463,6 +1489,9 @@ namespace Mono.CSharp {
                {
                        if (iface_exprs != null) {
                                foreach (TypeExpr iface in iface_exprs) {
+                                       if (iface == null)
+                                               continue;
+
                                        var iface_type = iface.Type;
 
                                        // Ensure the base is always setup
@@ -1494,7 +1523,7 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       if (base_type_expr != null) {
+                       if (base_type != null) {
                                ObsoleteAttribute obsolete_attr = base_type.GetAttributeObsolete ();
                                if (obsolete_attr != null && !IsObsolete)
                                        AttributeTester.Report_ObsoleteMessage (obsolete_attr, base_type.GetSignatureForError (), Location, Report);
@@ -1502,9 +1531,12 @@ namespace Mono.CSharp {
                                var ct = base_type_expr as GenericTypeExpr;
                                if (ct != null)
                                        ct.CheckConstraints (this);
-                       }
 
-                       if (base_type != null) {
+                               if (base_type.Interfaces != null) {
+                                       foreach (var iface in base_type.Interfaces)
+                                               spec.AddInterface (iface);
+                               }
+
                                var baseContainer = base_type.MemberDefinition as ClassOrStruct;
                                if (baseContainer != null) {
                                        baseContainer.Define ();
@@ -1555,6 +1587,10 @@ namespace Mono.CSharp {
                        ComputeIndexerName();
                        CheckEqualsAndGetHashCode();
 
+                       if (Kind == MemberKind.Interface && iface_exprs != null) {
+                               MemberCache.RemoveHiddenMembers (spec);
+                       }
+
                        return true;
                }
 
@@ -1613,13 +1649,16 @@ namespace Mono.CSharp {
                        if (!seen_normal_indexers)
                                return;
 
-                       PredefinedAttribute pa = Compiler.PredefinedAttributes.DefaultMember;
+                       PredefinedAttribute pa = Module.PredefinedAttributes.DefaultMember;
                        if (pa.Constructor == null &&
                                !pa.ResolveConstructor (Location, TypeManager.string_type))
                                return;
 
-                       CustomAttributeBuilder cb = new CustomAttributeBuilder (pa.Constructor, new string [] { GetAttributeDefaultMember () });
-                       TypeBuilder.SetCustomAttribute (cb);
+                       var encoder = new AttributeEncoder ();
+                       encoder.Encode (GetAttributeDefaultMember ());
+                       encoder.EncodeEmptyNamedArguments ();
+
+                       pa.EmitAttribute (TypeBuilder, encoder);
                }
 
                protected virtual void CheckEqualsAndGetHashCode ()
@@ -1752,7 +1791,12 @@ namespace Mono.CSharp {
                        }
 
                        if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
-                               Compiler.PredefinedAttributes.CompilerGenerated.EmitAttribute (TypeBuilder);
+                               Module.PredefinedAttributes.CompilerGenerated.EmitAttribute (TypeBuilder);
+
+#if STATIC
+                       if ((TypeBuilder.Attributes & TypeAttributes.StringFormatMask) == 0 && Module.HasDefaultCharSet)
+                               TypeBuilder.__SetAttributes (TypeBuilder.Attributes | Module.DefaultCharSetType);
+#endif
 
                        base.Emit ();
                }
@@ -1858,7 +1902,7 @@ namespace Mono.CSharp {
                        }
                }
 
-               public void CloseType ()
+               public virtual void CloseType ()
                {
                        if ((caching_flags & Flags.CloseTypeCreated) != 0)
                                return;
@@ -1866,8 +1910,12 @@ namespace Mono.CSharp {
                        // Close base type container first to avoid TypeLoadException
                        if (spec.BaseType != null) {
                                var btype = spec.BaseType.MemberDefinition as TypeContainer;
-                               if (btype != null)
+                               if (btype != null) {
                                        btype.CloseType ();
+
+                                       if ((caching_flags & Flags.CloseTypeCreated) != 0)
+                                               return;
+                               }
                        }
 
                        try {
@@ -2051,11 +2099,87 @@ namespace Mono.CSharp {
                        return false;
                }
 
+               bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
+               {
+                       return Module.DeclaringAssembly == assembly;
+               }
+
                public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
                {
                        throw new NotSupportedException ("Not supported for compiled definition " + GetSignatureForError ());
                }
 
+               //
+               // Public function used to locate types.
+               //
+               // Set 'ignore_cs0104' to true if you want to ignore cs0104 errors.
+               //
+               // Returns: Type or null if they type can not be found.
+               //
+               public override FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
+               {
+                       FullNamedExpression e;
+                       if (arity == 0 && Cache.TryGetValue (name, out e))
+                               return e;
+
+                       e = null;
+                       int errors = Report.Errors;
+
+                       if (arity == 0) {
+                               TypeParameter[] tp = CurrentTypeParameters;
+                               if (tp != null) {
+                                       TypeParameter tparam = TypeParameter.FindTypeParameter (tp, name);
+                                       if (tparam != null)
+                                               e = new TypeParameterExpr (tparam, Location.Null);
+                               }
+                       }
+
+                       if (e == null) {
+                               TypeSpec t = LookupNestedTypeInHierarchy (name, arity);
+
+                               if (t != null)
+                                       e = new TypeExpression (t, Location.Null);
+                               else if (Parent != null) {
+                                       e = Parent.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
+                               } else
+                                       e = NamespaceEntry.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
+                       }
+
+                       // TODO MemberCache: How to cache arity stuff ?
+                       if (errors == Report.Errors && arity == 0)
+                               Cache[name] = e;
+
+                       return e;
+               }
+
+               TypeSpec LookupNestedTypeInHierarchy (string name, int arity)
+               {
+                       // TODO: GenericMethod only
+                       if (PartialContainer == null)
+                               return null;
+
+                       // Has any nested type
+                       // Does not work, because base type can have
+                       //if (PartialContainer.Types == null)
+                       //      return null;
+
+                       var container = PartialContainer.CurrentType;
+
+                       // Is not Root container
+                       if (container == null)
+                               return null;
+
+                       var t = MemberCache.FindNestedType (container, name, arity);
+                       if (t == null)
+                               return null;
+
+                       // FIXME: Breaks error reporting
+                       if (!t.IsAccessible (CurrentType))
+                               return null;
+
+                       return t;
+               }
+
                public void Mark_HasEquals ()
                {
                        cached_method |= CachedMethods.Equals;
@@ -2112,7 +2236,7 @@ namespace Mono.CSharp {
 
        public abstract class ClassOrStruct : TypeContainer
        {
-               Dictionary<SecurityAction, PermissionSet> declarative_security;
+               SecurityType declarative_security;
 
                public ClassOrStruct (NamespaceEntry ns, DeclSpace parent,
                                      MemberName name, Attributes attrs, MemberKind kind)
@@ -2154,22 +2278,23 @@ namespace Mono.CSharp {
                                                Report.Warning (67, 3, e.Location, "The event `{0}' is never used", e.GetSignatureForError ());
                                }
                        }
+
+                       if (types != null) {
+                               foreach (var t in types)
+                                       t.VerifyMembers ();
+                       }
                }
 
                public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
                {
                        if (a.IsValidSecurityAttribute ()) {
-                               if (declarative_security == null)
-                                       declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
-
-                               a.ExtractSecurityPermissionSet (declarative_security);
+                               a.ExtractSecurityPermissionSet (ctor, ref declarative_security);
                                return;
                        }
 
                        if (a.Type == pa.StructLayout) {
                                PartialContainer.HasStructLayout = true;
-
-                               if (a.GetLayoutKindValue () == LayoutKind.Explicit)
+                               if (a.IsExplicitLayoutKind ())
                                        PartialContainer.HasExplicitLayout = true;
                        }
 
@@ -2229,7 +2354,11 @@ namespace Mono.CSharp {
 
                        if (declarative_security != null) {
                                foreach (var de in declarative_security) {
+#if STATIC
+                                       TypeBuilder.__AddDeclarativeSecurity (de);
+#else
                                        TypeBuilder.AddDeclarativeSecurity (de.Key, de.Value);
+#endif
                                }
                        }
                }
@@ -2400,14 +2529,10 @@ namespace Mono.CSharp {
                        base.Emit ();
 
                        if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
-                               Compiler.PredefinedAttributes.Extension.EmitAttribute (TypeBuilder);
+                               Module.PredefinedAttributes.Extension.EmitAttribute (TypeBuilder);
 
-                       var trans_flags = TypeManager.HasDynamicTypeUsed (base_type);
-                       if (trans_flags != null) {
-                               var pa = Compiler.PredefinedAttributes.DynamicTransform;
-                               if (pa.Constructor != null || pa.ResolveConstructor (Location, ArrayContainer.MakeType (TypeManager.bool_type))) {
-                                       TypeBuilder.SetCustomAttribute (new CustomAttributeBuilder (pa.Constructor, new object[] { trans_flags }));
-                               }
+                       if (base_type != null && base_type.HasDynamicElement) {
+                               Module.PredefinedAttributes.Dynamic.EmitAttribute (TypeBuilder, base_type, Location);
                        }
                }
 
@@ -2439,7 +2564,7 @@ namespace Mono.CSharp {
                                                GetSignatureForError (), base_class.GetSignatureForError ());
                                }
 
-                               if (base_type is PredefinedTypeSpec && !(spec is PredefinedTypeSpec) &&
+                               if (base_type is BuildinTypeSpec && !(spec is BuildinTypeSpec) &&
                                        (base_type == TypeManager.enum_type || base_type == TypeManager.value_type || base_type == TypeManager.multicast_delegate_type ||
                                        base_type == TypeManager.delegate_type || base_type == TypeManager.array_type)) {
                                        Report.Error (644, Location, "`{0}' cannot derive from special class `{1}'",
@@ -2476,7 +2601,7 @@ namespace Mono.CSharp {
                        if (OptAttributes == null)
                                return null;
 
-                       Attribute[] attrs = OptAttributes.SearchMulti (Compiler.PredefinedAttributes.Conditional);
+                       Attribute[] attrs = OptAttributes.SearchMulti (Module.PredefinedAttributes.Conditional);
                        if (attrs == null)
                                return null;
 
@@ -2540,13 +2665,19 @@ namespace Mono.CSharp {
                        //
                        // When struct constains fixed fixed and struct layout has explicitly
                        // set CharSet, its value has to be propagated to compiler generated
-                       // fixed field types
+                       // fixed types
                        //
-                       if (a.Type == pa.StructLayout && Fields != null && a.HasField ("CharSet")) {
+                       if (a.Type == pa.StructLayout && Fields != null) {
+                               var value = a.GetNamedValue ("CharSet");
+                               if (value == null)
+                                       return;
+
                                for (int i = 0; i < Fields.Count; ++i) {
                                        FixedField ff = Fields [i] as FixedField;
-                                       if (ff != null)
-                                               ff.SetCharSet (TypeBuilder.Attributes);
+                                       if (ff == null)
+                                               continue;
+
+                                       ff.CharSet = (CharSet) System.Enum.Parse (typeof (CharSet), value.GetValue ().ToString ());
                                }
                        }
                }
@@ -2565,7 +2696,7 @@ namespace Mono.CSharp {
                                if (!ftype.IsStruct)
                                        continue;
 
-                               if (ftype is PredefinedTypeSpec)
+                               if (ftype is BuildinTypeSpec)
                                        continue;
 
                                foreach (var targ in ftype.TypeArguments) {
@@ -2880,13 +3011,13 @@ namespace Mono.CSharp {
 
                                ObsoleteAttribute oa = base_member.GetAttributeObsolete ();
                                if (oa != null) {
-                                       if (OptAttributes == null || !OptAttributes.Contains (Compiler.PredefinedAttributes.Obsolete)) {
+                                       if (OptAttributes == null || !OptAttributes.Contains (Module.PredefinedAttributes.Obsolete)) {
                                                Report.SymbolRelatedToPreviousError (base_member);
                                                Report.Warning (672, 1, Location, "Member `{0}' overrides obsolete member `{1}'. Add the Obsolete attribute to `{0}'",
                                                        GetSignatureForError (), TypeManager.GetFullNameSignature (base_member));
                                        }
                                } else {
-                                       if (OptAttributes != null && OptAttributes.Contains (Compiler.PredefinedAttributes.Obsolete)) {
+                                       if (OptAttributes != null && OptAttributes.Contains (Module.PredefinedAttributes.Obsolete)) {
                                                Report.SymbolRelatedToPreviousError (base_member);
                                                Report.Warning (809, 1, Location, "Obsolete member `{0}' overrides non-obsolete member `{1}'",
                                                        GetSignatureForError (), TypeManager.GetFullNameSignature (base_member));
@@ -2910,13 +3041,15 @@ namespace Mono.CSharp {
                        } else {
                                if ((ModFlags & Modifiers.NEW) == 0) {
                                        ModFlags |= Modifiers.NEW;
-                                       Report.SymbolRelatedToPreviousError (base_member);
-                                       if (!IsInterface && (base_member.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
-                                               Report.Warning (114, 2, Location, "`{0}' hides inherited member `{1}'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword",
-                                                       GetSignatureForError (), base_member.GetSignatureForError ());
-                                       } else {
-                                               Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
-                                                       GetSignatureForError (), base_member.GetSignatureForError ());
+                                       if (!IsCompilerGenerated) {
+                                               Report.SymbolRelatedToPreviousError (base_member);
+                                               if (!IsInterface && (base_member.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
+                                                       Report.Warning (114, 2, Location, "`{0}' hides inherited member `{1}'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword",
+                                                               GetSignatureForError (), base_member.GetSignatureForError ());
+                                               } else {
+                                                       Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
+                                                               GetSignatureForError (), base_member.GetSignatureForError ());
+                                               }
                                        }
                                }
 
@@ -2981,34 +3114,30 @@ namespace Mono.CSharp {
                        var base_classp = base_member.Modifiers & Modifiers.AccessibilityMask;
 
                        if ((base_classp & (Modifiers.PROTECTED | Modifiers.INTERNAL)) == (Modifiers.PROTECTED | Modifiers.INTERNAL)) {
+                               //
+                               // It must be at least "protected"
+                               //
+                               if ((thisp & Modifiers.PROTECTED) == 0) {
+                                       return false;
+                               }
+
                                //
                                // when overriding protected internal, the method can be declared
                                // protected internal only within the same assembly or assembly
                                // which has InternalsVisibleTo
                                //
-                               if ((thisp & (Modifiers.PROTECTED | Modifiers.INTERNAL)) == (Modifiers.PROTECTED | Modifiers.INTERNAL)) {
-                                       return TypeManager.IsThisOrFriendAssembly (this_member.Assembly, base_member.Assembly);
-                               } 
-                               if ((thisp & Modifiers.PROTECTED) != Modifiers.PROTECTED) {
-                                       //
-                                       // if it's not "protected internal", it must be "protected"
-                                       //
-
-                                       return false;
-                               }
-                               if (this_member.Parent.PartialContainer.Module.Assembly == base_member.Assembly) {
-                                       //
-                                       // protected within the same assembly - an error
-                                       //
-                                       return false;
+                               if ((thisp & Modifiers.INTERNAL) != 0) {
+                                       return base_member.DeclaringType.MemberDefinition.IsInternalAsPublic (this_member.Module.DeclaringAssembly);
                                }
-                               if ((thisp & ~(Modifiers.PROTECTED | Modifiers.INTERNAL)) !=
-                                          (base_classp & ~(Modifiers.PROTECTED | Modifiers.INTERNAL))) {
-                                       //
-                                       // protected ok, but other attributes differ - report an error
-                                       //
+
+                               //
+                               // protected overriding protected internal inside same assembly
+                               // requires internal modifier as well
+                               //
+                               if (base_member.DeclaringType.MemberDefinition.IsInternalAsPublic (this_member.Module.DeclaringAssembly)) {
                                        return false;
                                }
+
                                return true;
                        }
 
@@ -3129,11 +3258,18 @@ namespace Mono.CSharp {
 
                protected void Error_CannotChangeAccessModifiers (MemberCore member, MemberSpec base_member)
                {
+                       var base_modifiers = base_member.Modifiers;
+
+                       // Remove internal modifier from types which are not internally accessible
+                       if ((base_modifiers & Modifiers.AccessibilityMask) == (Modifiers.PROTECTED | Modifiers.INTERNAL) &&
+                               !base_member.DeclaringType.MemberDefinition.IsInternalAsPublic (member.Module.DeclaringAssembly))
+                               base_modifiers = Modifiers.PROTECTED;
+
                        Report.SymbolRelatedToPreviousError (base_member);
                        Report.Error (507, member.Location,
                                "`{0}': cannot change access modifiers when overriding `{1}' inherited member `{2}'",
                                member.GetSignatureForError (),
-                               ModifiersExtensions.AccessibilityName (base_member.Modifiers),
+                               ModifiersExtensions.AccessibilityName (base_modifiers),
                                base_member.GetSignatureForError ());
                }