[mcs] Initial by ref returns and variables support
[mono.git] / mcs / mcs / property.cs
index 339d42d8f6753c1fad8a13f00ee0a4f5f1935a5d..3478711470a0fa6d93b668621c5d60392e2fda08 100644 (file)
@@ -17,7 +17,7 @@ using System.Collections.Generic;
 using System.Text;
 using Mono.CompilerServices.SymbolWriter;
 
-#if NET_2_1
+#if MOBILE
 using XmlElement = System.Object;
 #endif
 
@@ -82,8 +82,6 @@ namespace Mono.CSharp
                        }
                }
 
-               public abstract void PrepareEmit ();
-
                protected override bool VerifyClsCompliance ()
                {
                        if (!base.VerifyClsCompliance ())
@@ -246,7 +244,7 @@ namespace Mono.CSharp
                        protected override void ApplyToExtraTarget (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
                        {
                                if (a.Target == AttributeTargets.Parameter) {
-                                       parameters[0].ApplyAttributeBuilder (a, ctor, cdata, pa);
+                                       parameters[parameters.Count - 1].ApplyAttributeBuilder (a, ctor, cdata, pa);
                                        return;
                                }
 
@@ -337,18 +335,22 @@ namespace Mono.CSharp
                                        ModFlags |= method.ModFlags;
                                        flags = method.flags;
                                } else {
-                                       if (container.Kind == MemberKind.Interface)
+                                       CheckModifiers (ModFlags);
+                                       ModFlags |= (method.ModFlags & (~Modifiers.AccessibilityMask));
+                                       ModFlags |= Modifiers.PROPERTY_CUSTOM;
+
+                                       if (container.Kind == MemberKind.Interface) {
                                                Report.Error (275, Location, "`{0}': accessibility modifiers may not be used on accessors in an interface",
                                                        GetSignatureForError ());
-                                       else if ((method.ModFlags & Modifiers.ABSTRACT) != 0 && (ModFlags & Modifiers.PRIVATE) != 0) {
-                                               Report.Error (442, Location, "`{0}': abstract properties cannot have private accessors", GetSignatureForError ());
+                                       } else if ((ModFlags & Modifiers.PRIVATE) != 0) {
+                                               if ((method.ModFlags & Modifiers.ABSTRACT) != 0) {
+                                                       Report.Error (442, Location, "`{0}': abstract properties cannot have private accessors", GetSignatureForError ());
+                                               }
+
+                                               ModFlags &= ~Modifiers.VIRTUAL;
                                        }
 
-                                       CheckModifiers (ModFlags);
-                                       ModFlags |= (method.ModFlags & (~Modifiers.AccessibilityMask));
-                                       ModFlags |= Modifiers.PROPERTY_CUSTOM;
-                                       flags = ModifiersExtensions.MethodAttr (ModFlags);
-                                       flags |= (method.flags & (~MethodAttributes.MemberAccessMask));
+                                       flags = ModifiersExtensions.MethodAttr (ModFlags) | MethodAttributes.SpecialName;
                                }
 
                                CheckAbstractAndExtern (block != null);
@@ -512,7 +514,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);
@@ -522,14 +533,36 @@ namespace Mono.CSharp
                                                ok = false;
                                        }
                                } else if (Get.HasCustomAccessModifier || base_prop.HasDifferentAccessibility) {
-                                       if (!CheckAccessModifiers (Get, base_prop.Get)) {
+                                       if (!base_prop.Get.IsAccessible (this)) {
+                                               // Same as csc but it should be different error code
+                                               Report.Error (115, Get.Location, "`{0}' is marked as an override but no accessible `get' accessor found to override",
+                                                       GetSignatureForError ());
+                                               ok = false;
+                                       } else if (!CheckAccessModifiers (Get, base_prop.Get)) {
                                                Error_CannotChangeAccessModifiers (Get, base_prop.Get);
                                                ok = false;
                                        }
                                }
                        }
 
-                       if (Set != null) {
+                       if (Set == null) {
+                               if (base_prop.HasSet) {
+                                       if ((ModFlags & Modifiers.SEALED) != 0 && !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;
+                                       }
+
+                                       if ((ModFlags & Modifiers.AutoProperty) != 0) {
+                                               Report.Error (8080, Location, "`{0}': Auto-implemented properties must override all accessors of the overridden property",
+                                                       GetSignatureForError ());
+                                               ok = false;
+                                       }
+                               }
+                       } else {
                                if (!base_prop.HasSet) {
                                        if (ok) {
                                                Report.SymbolRelatedToPreviousError (base_prop);
@@ -539,7 +572,12 @@ namespace Mono.CSharp
                                                ok = false;
                                        }
                                } else if (Set.HasCustomAccessModifier || base_prop.HasDifferentAccessibility) {
-                                       if (!CheckAccessModifiers (Set, base_prop.Set)) {
+                                       if (!base_prop.Set.IsAccessible (this)) {
+                                               // Same as csc but it should be different error code
+                                               Report.Error (115, Set.Location, "`{0}' is marked as an override but no accessible `set' accessor found to override",
+                                                       GetSignatureForError ());
+                                               ok = false;
+                                       } else if (!CheckAccessModifiers (Set, base_prop.Set)) {
                                                Error_CannotChangeAccessModifiers (Set, base_prop.Set);
                                                ok = false;
                                        }
@@ -579,8 +617,7 @@ namespace Mono.CSharp
                                                GetSignatureForError ());
                                }
                        } else if ((ModFlags & Modifiers.OVERRIDE) == 0 && 
-                               (Get == null && (Set.ModFlags & Modifiers.AccessibilityMask) != 0) ||
-                               (Set == null && (Get.ModFlags & Modifiers.AccessibilityMask) != 0)) {
+                               ((Get == null && (Set.ModFlags & Modifiers.AccessibilityMask) != 0) || (Set == null && (Get.ModFlags & Modifiers.AccessibilityMask) != 0))) {
                                Report.Error (276, Location, 
                                              "`{0}': accessibility modifiers on accessors may only be used if the property or indexer has both a get and a set accessor",
                                              GetSignatureForError ());
@@ -643,6 +680,10 @@ namespace Mono.CSharp
                                Module.PredefinedAttributes.Dynamic.EmitAttribute (PropertyBuilder, member_type, Location);
                        }
 
+                       if (member_type.HasNamedTupleElement) {
+                               Module.PredefinedAttributes.TupleElementNames.EmitAttribute (PropertyBuilder, member_type, Location);
+                       }
+
                        ConstraintChecker.Check (this, member_type, type_expr.Location);
 
                        first.Emit (Parent);
@@ -710,16 +751,18 @@ namespace Mono.CSharp
                        
        public class Property : PropertyBase
        {
-               public sealed class BackingField : Field
+               public sealed class BackingFieldDeclaration : 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 BackingFieldDeclaration (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 {
@@ -736,8 +779,6 @@ 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,
@@ -748,6 +789,10 @@ namespace Mono.CSharp
                {
                }
 
+               public BackingFieldDeclaration BackingField { get; private set; }
+
+               public Expression Initializer { get; set; }
+
                public override void Accept (StructuralVisitor visitor)
                {
                        visitor.Visit (this);
@@ -756,7 +801,7 @@ namespace Mono.CSharp
                public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
                {
                        if (a.Target == AttributeTargets.Field) {
-                               backing_field.ApplyAttributeBuilder (a, ctor, cdata, pa);
+                               BackingField.ApplyAttributeBuilder (a, ctor, cdata, pa);
                                return;
                        }
 
@@ -766,15 +811,23 @@ namespace Mono.CSharp
                void CreateAutomaticProperty ()
                {
                        // Create backing field
-                       backing_field = new BackingField (this);
-                       if (!backing_field.Define ())
+                       BackingField = new BackingFieldDeclaration (this, Initializer == null && Set == null);
+                       if (!BackingField.Define ())
                                return;
 
-                       Parent.PartialContainer.Members.Add (backing_field);
+                       if (Initializer != null) {
+                               BackingField.Initializer = Initializer;
+                               Parent.RegisterFieldForInitialization (BackingField, new FieldInitializer (BackingField, Initializer, Location));
+                               BackingField.ModFlags |= Modifiers.READONLY;
+                       }
+
+                       Parent.PartialContainer.Members.Add (BackingField);
 
-                       FieldExpr fe = new FieldExpr (backing_field, Location);
-                       if ((backing_field.ModFlags & Modifiers.STATIC) == 0)
+                       FieldExpr fe = new FieldExpr (BackingField, Location);
+                       if ((BackingField.ModFlags & Modifiers.STATIC) == 0) {
                                fe.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location);
+                               Parent.PartialContainer.HasInstanceField = true;
+                       }
 
                        //
                        // Create get block but we careful with location to
@@ -784,11 +837,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 ()
@@ -798,13 +855,38 @@ 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 (8052, 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) {
+                               ModFlags |= Modifiers.AutoProperty;
+                               if (Get == null) {
+                                       Report.Error (8051, Location, "Auto-implemented property `{0}' must have get accessor",
+                                               GetSignatureForError ());
+                                       return false;
+                               }
+
+                               if (MemberType.Kind == MemberKind.ByRef) {
+                                       Report.Error (8145, Location, "Auto-implemented properties cannot return by reference");
+                                       return false;
+                               }
+
+                               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 ();
                        }
 
@@ -830,7 +912,7 @@ namespace Mono.CSharp
 
                public override void Emit ()
                {
-                       if ((AccessorFirst.ModFlags & (Modifiers.STATIC | Modifiers.COMPILER_GENERATED)) == Modifiers.COMPILER_GENERATED && Parent.PartialContainer.HasExplicitLayout) {
+                       if ((AccessorFirst.ModFlags & (Modifiers.STATIC | Modifiers.AutoProperty)) == Modifiers.AutoProperty && Parent.PartialContainer.HasExplicitLayout) {
                                Report.Error (842, Location,
                                        "Automatically implemented property `{0}' cannot be used inside a type with an explicit StructLayout attribute",
                                        GetSignatureForError ());
@@ -984,13 +1066,22 @@ 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) {
+                                       if (Module.PredefinedMembers.MonitorEnter_v4.Get () != null || Module.PredefinedMembers.MonitorEnter.Get () != 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 {
+                                               Module.PredefinedMembers.InterlockedCompareExchange_T.Resolve (Location);
+                                       }
+                               } else {
+                                       body.AddStatement (new StatementExpression (new SimpleAssign (
+                                               new LocalVariableReference (obj1, Location),
+                                               new Invocation (MethodGroupExpr.CreatePredefined (cas, cas.DeclaringType, Location), args))));
+                               }
                        }
                }
 
@@ -1130,12 +1221,11 @@ namespace Mono.CSharp
 
                        backing_field = new Field (Parent,
                                new TypeExpression (MemberType, Location),
-                               Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | (ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)),
+                               Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN | Modifiers.PRIVATE | (ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)),
                                MemberName, null);
 
                        Parent.PartialContainer.Members.Add (backing_field);
                        backing_field.Initializer = Initializer;
-                       backing_field.ModFlags &= ~Modifiers.COMPILER_GENERATED;
 
                        // Call define because we passed fields definition
                        backing_field.Define ();
@@ -1369,6 +1459,8 @@ namespace Mono.CSharp
 
                public override void PrepareEmit ()
                {
+                       base.PrepareEmit ();
+
                        add.PrepareEmit ();
                        remove.PrepareEmit ();
 
@@ -1676,6 +1768,12 @@ namespace Mono.CSharp
                        return base.GetSignatureForDocumentation () + parameters.GetSignatureForDocumentation ();
                }
 
+               public override void PrepareEmit ()
+               {
+                       base.PrepareEmit ();
+                       parameters.ResolveDefaultValues (this);
+               }
+
                protected override bool VerifyClsCompliance ()
                {
                        if (!base.VerifyClsCompliance ())
@@ -1704,6 +1802,18 @@ namespace Mono.CSharp
                }
                #endregion
 
+               public static ParametersImported CreateParametersFromSetter (MethodSpec setter, int set_param_count)
+               {
+                       //
+                       // Creates 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 (setter.Parameters.FixedParameters, data, set_param_count);
+                       Array.Copy (setter.Parameters.Types, types, set_param_count);
+                       return new ParametersImported (data, types, setter.Parameters.HasParams);
+               }
+
                public override string GetSignatureForDocumentation ()
                {
                        return base.GetSignatureForDocumentation () + parameters.GetSignatureForDocumentation ();