Merge pull request #1229 from andreiagaita/master
[mono.git] / mcs / mcs / property.cs
index 327c58c60839155d452ed05d7e118e659f1c8372..36283fdc19797f0edab39160bfdd38fbad0bab26 100644 (file)
@@ -35,7 +35,7 @@ namespace Mono.CSharp
        // This includes properties, indexers, and events
        public abstract class PropertyBasedMember : InterfaceMemberBase
        {
-               public PropertyBasedMember (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name, Attributes attrs)
+               protected PropertyBasedMember (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name, Attributes attrs)
                        : base (parent, type, mod, allowed_mod, name, attrs)
                {
                }
@@ -82,6 +82,8 @@ namespace Mono.CSharp
                        }
                }
 
+               public abstract void PrepareEmit ();
+
                protected override bool VerifyClsCompliance ()
                {
                        if (!base.VerifyClsCompliance ())
@@ -174,9 +176,9 @@ namespace Mono.CSharp
                        return ps;
                }
 
-               public override List<TypeSpec> ResolveMissingDependencies ()
+               public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
                {
-                       return memberType.ResolveMissingDependencies ();
+                       return memberType.ResolveMissingDependencies (this);
                }
        }
 
@@ -197,7 +199,7 @@ namespace Mono.CSharp
                        {
                        }
 
-                       public override MethodBuilder Define (TypeContainer parent)
+                       public override void Define (TypeContainer parent)
                        {
                                base.Define (parent);
 
@@ -205,12 +207,7 @@ namespace Mono.CSharp
 
                                method_data = new MethodData (method, ModFlags, flags, this);
 
-                               if (!method_data.Define (parent.PartialContainer, method.GetFullName (MemberName)))
-                                       return null;
-
-                               method_data.DefineMethodBuilder (parent.PartialContainer, ParameterInfo);
-
-                               return method_data.MethodBuilder;
+                               method_data.Define (parent.PartialContainer, method.GetFullName (MemberName));
                        }
 
                        public override TypeSpec ReturnType {
@@ -253,7 +250,7 @@ namespace Mono.CSharp
                                        return;
                                }
 
-                               base.ApplyAttributeBuilder (a, ctor, cdata, pa);
+                               base.ApplyToExtraTarget (a, ctor, cdata, pa);
                        }
 
                        public override ParametersCompiled ParameterInfo {
@@ -262,7 +259,7 @@ namespace Mono.CSharp
                            }
                        }
 
-                       public override MethodBuilder Define (TypeContainer parent)
+                       public override void Define (TypeContainer parent)
                        {
                                parameters.Resolve (this);
                                
@@ -272,12 +269,7 @@ namespace Mono.CSharp
 
                                method_data = new MethodData (method, ModFlags, flags, this);
 
-                               if (!method_data.Define (parent.PartialContainer, method.GetFullName (MemberName)))
-                                       return null;
-
-                               method_data.DefineMethodBuilder (parent.PartialContainer, ParameterInfo);
-
-                               return method_data.MethodBuilder;
+                               method_data.Define (parent.PartialContainer, method.GetFullName (MemberName));
                        }
 
                        public override TypeSpec ReturnType {
@@ -334,7 +326,7 @@ namespace Mono.CSharp
                                return method.IsClsComplianceRequired ();
                        }
 
-                       public virtual MethodBuilder Define (TypeContainer parent)
+                       public virtual void Define (TypeContainer parent)
                        {
                                var container = parent.PartialContainer;
 
@@ -369,8 +361,6 @@ namespace Mono.CSharp
                                        if (Compiler.Settings.WriteMetadataOnly)
                                                block = null;
                                }
-
-                               return null;
                        }
 
                        public bool HasCustomAccessModifier {
@@ -408,7 +398,7 @@ namespace Mono.CSharp
                PropertyMethod get, set, first;
                PropertyBuilder PropertyBuilder;
 
-               public PropertyBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, Modifiers allowed_mod, MemberName name, Attributes attrs)
+               protected PropertyBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, Modifiers allowed_mod, MemberName name, Attributes attrs)
                        : base (parent, type, mod_flags, allowed_mod, name, attrs)
                {
                }
@@ -522,7 +512,16 @@ namespace Mono.CSharp
                        // Check base property accessors conflict
                        //
                        var base_prop = (PropertySpec) base_member;
-                       if (Get != null) {
+                       if (Get == null) {
+                               if ((ModFlags & Modifiers.SEALED) != 0 && base_prop.HasGet && !base_prop.Get.IsAccessible (this)) {
+                                       // TODO: Should be different error code but csc uses for some reason same
+                                       Report.SymbolRelatedToPreviousError (base_prop);
+                                       Report.Error (545, Location,
+                                               "`{0}': cannot override because `{1}' does not have accessible get accessor",
+                                               GetSignatureForError (), base_prop.GetSignatureForError ());
+                                       ok = false;
+                               }
+                       } else {
                                if (!base_prop.HasGet) {
                                        if (ok) {
                                                Report.SymbolRelatedToPreviousError (base_prop);
@@ -539,7 +538,16 @@ namespace Mono.CSharp
                                }
                        }
 
-                       if (Set != null) {
+                       if (Set == null) {
+                               if ((ModFlags & Modifiers.SEALED) != 0 && base_prop.HasSet && !base_prop.Set.IsAccessible (this)) {
+                                       // TODO: Should be different error code but csc uses for some reason same
+                                       Report.SymbolRelatedToPreviousError (base_prop);
+                                       Report.Error (546, Location,
+                                               "`{0}': cannot override because `{1}' does not have accessible set accessor",
+                                               GetSignatureForError (), base_prop.GetSignatureForError ());
+                                       ok = false;
+                               }
+                       } else {
                                if (!base_prop.HasSet) {
                                        if (ok) {
                                                Report.SymbolRelatedToPreviousError (base_prop);
@@ -624,24 +632,14 @@ namespace Mono.CSharp
 
                        if (Get != null) {
                                spec.Get = Get.Spec;
-
-                               var method = Get.Spec.GetMetaInfo () as MethodBuilder;
-                               if (method != null) {
-                                       PropertyBuilder.SetGetMethod (method);
-                                       Parent.MemberCache.AddMember (this, method.Name, Get.Spec);
-                               }
+                               Parent.MemberCache.AddMember (this, Get.Spec.Name, Get.Spec);
                        } else {
                                CheckMissingAccessor (kind, parameters, true);
                        }
 
                        if (Set != null) {
                                spec.Set = Set.Spec;
-
-                               var method = Set.Spec.GetMetaInfo () as MethodBuilder;
-                               if (method != null) {
-                                       PropertyBuilder.SetSetMethod (method);
-                                       Parent.MemberCache.AddMember (this, method.Name, Set.Spec);
-                               }
+                               Parent.MemberCache.AddMember (this, Set.Spec.Name, Set.Spec);
                        } else {
                                CheckMissingAccessor (kind, parameters, false);
                        }
@@ -681,6 +679,25 @@ namespace Mono.CSharp
                        }
                }
 
+               public override void PrepareEmit ()
+               {
+                       AccessorFirst.PrepareEmit ();
+                       if (AccessorSecond != null)
+                               AccessorSecond.PrepareEmit ();
+
+                       if (get != null) {
+                               var method = Get.Spec.GetMetaInfo () as MethodBuilder;
+                               if (method != null)
+                                       PropertyBuilder.SetGetMethod (method);
+                       }
+
+                       if (set != null) {
+                               var method = Set.Spec.GetMetaInfo () as MethodBuilder;
+                               if (method != null)
+                                       PropertyBuilder.SetSetMethod (method);
+                       }
+               }
+
                protected override void SetMemberName (MemberName new_name)
                {
                        base.SetMemberName (new_name);
@@ -714,13 +731,15 @@ namespace Mono.CSharp
                public sealed class BackingField : Field
                {
                        readonly Property property;
+                       const Modifiers DefaultModifiers = Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | Modifiers.DEBUGGER_HIDDEN;
 
-                       public BackingField (Property p)
-                               : base (p.Parent, p.type_expr,
-                               Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | (p.ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)),
+                       public BackingField (Property p, bool readOnly)
+                               : base (p.Parent, p.type_expr, DefaultModifiers | (p.ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)),
                                new MemberName ("<" + p.GetFullName (p.MemberName) + ">k__BackingField", p.Location), null)
                        {
                                this.property = p;
+                               if (readOnly)
+                                       ModFlags |= Modifiers.READONLY;
                        }
 
                        public Property OriginalProperty {
@@ -735,6 +754,10 @@ namespace Mono.CSharp
                        }
                }
 
+               static readonly string[] attribute_target_auto = new string[] { "property", "field" };
+
+               Field backing_field;
+
                public Property (TypeDefinition parent, FullNamedExpression type, Modifiers mod,
                                 MemberName name, Attributes attrs)
                        : base (parent, type, mod,
@@ -745,23 +768,40 @@ namespace Mono.CSharp
                {
                }
 
+               public Expression Initializer { get; set; }
+
                public override void Accept (StructuralVisitor visitor)
                {
                        visitor.Visit (this);
                }
-               
+
+               public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
+               {
+                       if (a.Target == AttributeTargets.Field) {
+                               backing_field.ApplyAttributeBuilder (a, ctor, cdata, pa);
+                               return;
+                       }
+
+                       base.ApplyAttributeBuilder (a, ctor, cdata, pa);
+               }
 
                void CreateAutomaticProperty ()
                {
                        // Create backing field
-                       Field field = new BackingField (this);
-                       if (!field.Define ())
+                       backing_field = new BackingField (this, Initializer != null && Set == null);
+                       if (!backing_field.Define ())
                                return;
 
-                       Parent.PartialContainer.Members.Add (field);
+                       if (Initializer != null) {
+                               backing_field.Initializer = Initializer;
+                               Parent.RegisterFieldForInitialization (backing_field, new FieldInitializer (backing_field, Initializer, Location));
+                               backing_field.ModFlags |= Modifiers.READONLY;
+                       }
 
-                       FieldExpr fe = new FieldExpr (field, Location);
-                       if ((field.ModFlags & Modifiers.STATIC) == 0)
+                       Parent.PartialContainer.Members.Add (backing_field);
+
+                       FieldExpr fe = new FieldExpr (backing_field, Location);
+                       if ((backing_field.ModFlags & Modifiers.STATIC) == 0)
                                fe.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location);
 
                        //
@@ -772,11 +812,15 @@ namespace Mono.CSharp
                        Get.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location.Null);
                        Return r = new Return (fe, Get.Location);
                        Get.Block.AddStatement (r);
+                       Get.ModFlags |= Modifiers.COMPILER_GENERATED;
 
                        // Create set block
-                       Set.Block = new ToplevelBlock (Compiler, Set.ParameterInfo, Location.Null);
-                       Assign a = new SimpleAssign (fe, new SimpleName ("value", Location.Null), Location.Null);
-                       Set.Block.AddStatement (new StatementExpression (a, Set.Location));
+                       if (Set != null) {
+                               Set.Block = new ToplevelBlock (Compiler, Set.ParameterInfo, Location.Null);
+                               Assign a = new SimpleAssign (fe, new SimpleName ("value", Location.Null), Location.Null);
+                               Set.Block.AddStatement (new StatementExpression (a, Set.Location));
+                               Set.ModFlags |= Modifiers.COMPILER_GENERATED;
+                       }
                }
 
                public override bool Define ()
@@ -786,13 +830,37 @@ namespace Mono.CSharp
 
                        flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName;
 
-                       if (!IsInterface && (ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) == 0 &&
-                               AccessorSecond != null && Get.Block == null && Set.Block == null) {
-                               if (Compiler.Settings.Version <= LanguageVersion.ISO_2)
-                                       Report.FeatureIsNotAvailable (Compiler, Location, "automatically implemented properties");
+                       bool auto = AccessorFirst.Block == null && (AccessorSecond == null || AccessorSecond.Block == null) &&
+                               (ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) == 0;
+
+                       if (Initializer != null) {
+                               if (!auto)
+                                       Report.Error (8050, Location, "`{0}': Only auto-implemented properties can have initializers",
+                                               GetSignatureForError ());
+
+                               if (IsInterface)
+                                       Report.Error (8053, Location, "`{0}': Properties inside interfaces cannot have initializers",
+                                               GetSignatureForError ());
+
+                               if (Compiler.Settings.Version < LanguageVersion.V_6)
+                                       Report.FeatureIsNotAvailable (Compiler, Location, "auto-implemented property initializer");
+                       }
+
+                       if (auto) {
+                               if (Get == null) {
+                                       Report.Error (8052, Location, "Auto-implemented property `{0}' must have get accessor",
+                                               GetSignatureForError ());
+                                       return false;
+                               }
+
+                               if (Initializer == null && AccessorSecond == null) {
+                                       Report.Error (8051, Location, "Auto-implemented property `{0}' must have set accessor or initializer",
+                                               GetSignatureForError ());
+                               }
+
+                               if (Compiler.Settings.Version < LanguageVersion.V_3 && Initializer == null)
+                                       Report.FeatureIsNotAvailable (Compiler, Location, "auto-implemented properties");
 
-                               Get.ModFlags |= Modifiers.COMPILER_GENERATED;
-                               Set.ModFlags |= Modifiers.COMPILER_GENERATED;
                                CreateAutomaticProperty ();
                        }
 
@@ -826,6 +894,13 @@ namespace Mono.CSharp
 
                        base.Emit ();
                }
+
+               public override string[] ValidAttributeTargets {
+                       get {
+                               return Get != null && ((Get.ModFlags & Modifiers.COMPILER_GENERATED) != 0) ?
+                                       attribute_target_auto : base.ValidAttributeTargets;
+                       }
+               }
        }
 
        /// <summary>
@@ -839,10 +914,10 @@ namespace Mono.CSharp
                        {
                        }
 
-                       public override MethodBuilder Define (TypeContainer ds)
+                       public override void Define (TypeContainer ds)
                        {
                                CheckAbstractAndExtern (block != null);
-                               return base.Define (ds);
+                               base.Define (ds);
                        }
                        
                        public override string GetSignatureForError ()
@@ -965,13 +1040,18 @@ namespace Mono.CSharp
                                        Location)));
                                args.Add (new Argument (new LocalVariableReference (obj1, Location)));
 
-                               var cas = Module.PredefinedMembers.InterlockedCompareExchange_T.Resolve (Location);
-                               if (cas == null)
-                                       return;
-
-                               body.AddStatement (new StatementExpression (new SimpleAssign (
-                                       new LocalVariableReference (obj1, Location),
-                                       new Invocation (MethodGroupExpr.CreatePredefined (cas, cas.DeclaringType, Location), args))));
+                               var cas = Module.PredefinedMembers.InterlockedCompareExchange_T.Get ();
+                               if (cas == null) {
+                                       // Workaround for cripled (e.g. microframework) mscorlib without CompareExchange
+                                       body.AddStatement (new Lock (
+                                               block.GetParameterReference (0, Location),
+                                               new StatementExpression (new SimpleAssign (
+                                                       f_expr, args [1].Expr, Location), Location), Location));
+                               } else {
+                                       body.AddStatement (new StatementExpression (new SimpleAssign (
+                                               new LocalVariableReference (obj1, Location),
+                                               new Invocation (MethodGroupExpr.CreatePredefined (cas, cas.DeclaringType, Location), args))));
+                               }
                        }
                }
 
@@ -1089,8 +1169,8 @@ namespace Mono.CSharp
                                return false;
 
                        if (declarators != null) {
-                               if ((mod_flags_src & Modifiers.DEFAULT_ACCESS_MODIFER) != 0)
-                                       mod_flags_src &= ~(Modifiers.AccessibilityMask | Modifiers.DEFAULT_ACCESS_MODIFER);
+                               if ((mod_flags_src & Modifiers.DEFAULT_ACCESS_MODIFIER) != 0)
+                                       mod_flags_src &= ~(Modifiers.AccessibilityMask | Modifiers.DEFAULT_ACCESS_MODIFIER);
 
                                var t = new TypeExpression (MemberType, TypeExpression.Location);
                                foreach (var d in declarators) {
@@ -1109,9 +1189,6 @@ namespace Mono.CSharp
                                return true;
                        }
 
-                       if (Add.IsInterfaceImplementation)
-                               SetIsUsed ();
-
                        backing_field = new Field (Parent,
                                new TypeExpression (MemberType, Location),
                                Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | (ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)),
@@ -1171,7 +1248,7 @@ namespace Mono.CSharp
                                        return;
                                }
 
-                               base.ApplyAttributeBuilder (a, ctor, cdata, pa);
+                               base.ApplyToExtraTarget (a, ctor, cdata, pa);
                        }
 
                        public override AttributeTargets AttributeTargets {
@@ -1185,7 +1262,7 @@ namespace Mono.CSharp
                                return method.IsClsComplianceRequired ();
                        }
 
-                       public virtual MethodBuilder Define (TypeContainer parent)
+                       public virtual void Define (TypeContainer parent)
                        {
                                // Fill in already resolved event type to speed things up and
                                // avoid confusing duplicate errors
@@ -1196,17 +1273,13 @@ namespace Mono.CSharp
                                        method.flags | MethodAttributes.HideBySig | MethodAttributes.SpecialName, this);
 
                                if (!method_data.Define (parent.PartialContainer, method.GetFullName (MemberName)))
-                                       return null;
-
-                               method_data.DefineMethodBuilder (parent.PartialContainer, ParameterInfo);
+                                       return;
 
                                if (Compiler.Settings.WriteMetadataOnly)
                                        block = null;
 
                                Spec = new MethodSpec (MemberKind.Method, parent.PartialContainer.Definition, this, ReturnType, ParameterInfo, method.ModFlags);
                                Spec.IsAccessor = true;
-
-                               return method_data.MethodBuilder;
                        }
 
                        public override TypeSpec ReturnType {
@@ -1220,6 +1293,12 @@ namespace Mono.CSharp
                                return method.GetAttributeObsolete ();
                        }
 
+                       public MethodData MethodData {
+                               get {
+                                       return method_data;
+                               }
+                       }
+
                        public override string[] ValidAttributeTargets {
                                get {
                                        return attribute_targets;
@@ -1318,23 +1397,16 @@ namespace Mono.CSharp
                        //
                        // Now define the accessors
                        //
-                       var AddBuilder = Add.Define (Parent);
-                       if (AddBuilder == null)
-                               return false;
-
-                       var RemoveBuilder = remove.Define (Parent);
-                       if (RemoveBuilder == null)
-                               return false;
+                       add.Define (Parent);
+                       remove.Define (Parent);
 
                        EventBuilder = Parent.TypeBuilder.DefineEvent (GetFullName (MemberName), EventAttributes.None, MemberType.GetMetaInfo ());
-                       EventBuilder.SetAddOnMethod (AddBuilder);
-                       EventBuilder.SetRemoveOnMethod (RemoveBuilder);
 
                        spec = new EventSpec (Parent.Definition, this, MemberType, ModFlags, Add.Spec, remove.Spec);
 
                        Parent.MemberCache.AddMember (this, GetFullName (MemberName), spec);
-                       Parent.MemberCache.AddMember (this, AddBuilder.Name, Add.Spec);
-                       Parent.MemberCache.AddMember (this, RemoveBuilder.Name, remove.Spec);
+                       Parent.MemberCache.AddMember (this, Add.Spec.Name, Add.Spec);
+                       Parent.MemberCache.AddMember (this, Remove.Spec.Name, remove.Spec);
 
                        return true;
                }
@@ -1356,6 +1428,15 @@ namespace Mono.CSharp
                        base.Emit ();
                }
 
+               public override void PrepareEmit ()
+               {
+                       add.PrepareEmit ();
+                       remove.PrepareEmit ();
+
+                       EventBuilder.SetAddOnMethod (add.MethodData.MethodBuilder);
+                       EventBuilder.SetRemoveOnMethod (remove.MethodData.MethodBuilder);
+               }
+
                public override void WriteDebugSymbol (MonoSymbolFile file)
                {
                        add.WriteDebugSymbol (file);
@@ -1427,9 +1508,9 @@ namespace Mono.CSharp
                        return es;
                }
 
-               public override List<TypeSpec> ResolveMissingDependencies ()
+               public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
                {
-                       return MemberType.ResolveMissingDependencies ();
+                       return MemberType.ResolveMissingDependencies (this);
                }
        }
  
@@ -1445,7 +1526,7 @@ namespace Mono.CSharp
                                this.parameters = parameters;
                        }
 
-                       public override MethodBuilder Define (TypeContainer parent)
+                       public override void Define (TypeContainer parent)
                        {
                                // Disable reporting, parameters are resolved twice
                                Report.DisableReporting ();
@@ -1455,7 +1536,7 @@ namespace Mono.CSharp
                                        Report.EnableReporting ();
                                }
 
-                               return base.Define (parent);
+                               base.Define (parent);
                        }
 
                        public override ParametersCompiled ParameterInfo {
@@ -1701,16 +1782,17 @@ namespace Mono.CSharp
                        return spec;
                }
 
-               public override List<TypeSpec> ResolveMissingDependencies ()
+               public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
                {
-                       var missing = base.ResolveMissingDependencies ();
+                       var missing = base.ResolveMissingDependencies (caller);
+
                        foreach (var pt in parameters.Types) {
-                               var m = pt.GetMissingDependencies ();
+                               var m = pt.GetMissingDependencies (caller);
                                if (m == null)
                                        continue;
 
                                if (missing == null)
-                                       missing = new List<TypeSpec> ();
+                                       missing = new List<MissingTypeSpecReference> ();
 
                                missing.AddRange (m);
                        }