[mcs] auto-implemented property initializer
authorMarek Safar <marek.safar@gmail.com>
Thu, 10 Jul 2014 16:57:40 +0000 (18:57 +0200)
committerMarek Safar <marek.safar@gmail.com>
Thu, 10 Jul 2014 16:58:08 +0000 (18:58 +0200)
19 files changed:
mcs/errors/cs0573-2.cs [deleted file]
mcs/errors/cs0573.cs [deleted file]
mcs/errors/cs0840.cs [deleted file]
mcs/errors/cs1644-19.cs
mcs/errors/cs1644-36.cs [new file with mode: 0644]
mcs/errors/cs8050.cs [new file with mode: 0644]
mcs/errors/cs8051.cs [new file with mode: 0644]
mcs/errors/cs8052.cs [new file with mode: 0644]
mcs/errors/cs8053.cs [new file with mode: 0644]
mcs/errors/cs8054-2.cs [new file with mode: 0644]
mcs/errors/cs8054-3.cs [new file with mode: 0644]
mcs/errors/cs8054.cs [new file with mode: 0644]
mcs/mcs/class.cs
mcs/mcs/cs-parser.jay
mcs/mcs/flowanalysis.cs
mcs/mcs/membercache.cs
mcs/mcs/property.cs
mcs/tests/gtest-autoproperty-09.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_5.xml

diff --git a/mcs/errors/cs0573-2.cs b/mcs/errors/cs0573-2.cs
deleted file mode 100644 (file)
index 50836de..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// CS0573: `A.a': Structs cannot have instance field initializers
-// Line: 5
-
-partial struct A {
-       int a = 1;
-}
diff --git a/mcs/errors/cs0573.cs b/mcs/errors/cs0573.cs
deleted file mode 100644 (file)
index deec3ea..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// CS0573: `A.a': Structs cannot have instance field initializers
-// Line: 5
-struct A {
-       int a = 1;
-}
-
-class D {
-       static void Main ()
-       {
-               A [] a = new A [10];
-
-       }
-}
diff --git a/mcs/errors/cs0840.cs b/mcs/errors/cs0840.cs
deleted file mode 100644 (file)
index bc4ee41..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// CS0840: `Test.Property.get' must have a body because it is not marked abstract or extern. The property can be automatically implemented when you define both accessors
-// Line: 7
-
-
-public abstract class Test
-{
-       public string Property { get; }
-}
index ce867d1e71cdb59574562de4f94ffd663c657e8f..fe4e494dd375f2c7fd5d60a6c2e82e5578d0d7c8 100644 (file)
@@ -1,4 +1,4 @@
-// CS1644: Feature `automatically implemented properties' cannot be used because it is not part of the C# 2.0 language specification
+// CS1644: Feature `auto-implemented properties' cannot be used because it is not part of the C# 2.0 language specification
 // Line: 7
 // Compiler options: -langversion:ISO-2
 
diff --git a/mcs/errors/cs1644-36.cs b/mcs/errors/cs1644-36.cs
new file mode 100644 (file)
index 0000000..df2d30b
--- /dev/null
@@ -0,0 +1,8 @@
+// CS1644: Feature `auto-implemented property initializer' cannot be used because it is not part of the C# 5.0 language specification
+// Line: 7
+// Compiler options: -langversion:5
+
+class C
+{
+       public static int P { get; } = 4;
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8050.cs b/mcs/errors/cs8050.cs
new file mode 100644 (file)
index 0000000..2f4b88b
--- /dev/null
@@ -0,0 +1,7 @@
+// CS8050: `C.P': Only auto-implemented properties can have initializers
+// Line: 6
+
+abstract class C
+{
+       public abstract int P { get; } = 4;
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8051.cs b/mcs/errors/cs8051.cs
new file mode 100644 (file)
index 0000000..7935efb
--- /dev/null
@@ -0,0 +1,7 @@
+// CS8051: Auto-implemented property `Test.Property' must have set accessor or initializer
+// Line: 6
+
+public abstract class Test
+{
+       public string Property { get; }
+}
diff --git a/mcs/errors/cs8052.cs b/mcs/errors/cs8052.cs
new file mode 100644 (file)
index 0000000..bccf015
--- /dev/null
@@ -0,0 +1,7 @@
+// CS8052: Auto-implemented property `V.P' must have get accessor
+// Line: 6
+
+class V
+{
+       public object P { set; } = 1;
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8053.cs b/mcs/errors/cs8053.cs
new file mode 100644 (file)
index 0000000..319835f
--- /dev/null
@@ -0,0 +1,7 @@
+// CS8053: `I.P': Properties inside interfaces cannot have initializers
+// Line: 6
+
+interface I
+{
+       int P { get; } = 4;
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8054-2.cs b/mcs/errors/cs8054-2.cs
new file mode 100644 (file)
index 0000000..e633f17
--- /dev/null
@@ -0,0 +1,6 @@
+// CS0573: `A.a': Structs without explicit constructors cannot contain members with initializers
+// Line: 5
+
+partial struct A {
+       int a = 1;
+}
diff --git a/mcs/errors/cs8054-3.cs b/mcs/errors/cs8054-3.cs
new file mode 100644 (file)
index 0000000..b06047f
--- /dev/null
@@ -0,0 +1,6 @@
+// CS0573: `A.a': Structs without explicit constructors cannot contain members with initializers
+// Line: 5
+
+struct A {
+       int a = 1;
+}
diff --git a/mcs/errors/cs8054.cs b/mcs/errors/cs8054.cs
new file mode 100644 (file)
index 0000000..4b8fc2e
--- /dev/null
@@ -0,0 +1,7 @@
+// CS8054: `S.P': Structs without explicit constructors cannot contain members with initializers
+// Line: 6
+
+struct S
+{
+       public decimal P { get; } = -3;
+}
\ No newline at end of file
index 96f9188898788e19b823cbf611ae418e948d5408..289dc5fe2cac434faf054d4b5f78573f0a4aee35 100644 (file)
@@ -3049,6 +3049,20 @@ namespace Mono.CSharp
                        base.Emit ();
                }
 
+               bool HasExplicitConstructor ()
+               {
+                       foreach (var m in Members) {
+                               var c = m as Constructor;
+                               if (c == null)
+                                       continue;
+
+                               if (!c.ParameterInfo.IsEmpty)
+                                       return true;
+                       }
+
+                       return false;
+               }
+
                public override bool IsUnmanagedType ()
                {
                        if (has_unmanaged_check_done)
@@ -3104,14 +3118,15 @@ namespace Mono.CSharp
 
                public override void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression)
                {
-                       if ((field.ModFlags & Modifiers.STATIC) == 0) {
-                               Report.Error (573, field.Location, "`{0}': Structs cannot have instance field initializers",
+                       if ((field.ModFlags & Modifiers.STATIC) == 0 && !HasExplicitConstructor ()) {
+                               Report.Error (8054, field.Location, "`{0}': Structs without explicit constructors cannot contain members with initializers",
                                        field.GetSignatureForError ());
+
                                return;
                        }
+
                        base.RegisterFieldForInitialization (field, expression);
                }
-
        }
 
        /// <summary>
index e81ba26d18c5a98e8e07b13ecbd264c13d462b98..34d4cd33bec2d824ba51f9326f3cc2501e606d04 100644 (file)
@@ -1708,13 +1708,14 @@ arglist_modifier
                        report.Error (1669, GetLocation ($1), "__arglist is not valid in this context");
          }
        ;
-       
+
 property_declaration
        : opt_attributes
          opt_modifiers
          member_type
          member_declaration_name
          {
+               lexer.parsing_generic_declaration = false;
                if (doc_support)
                        tmpComment = Lexer.consume_doc_comment ();
          }
@@ -1742,10 +1743,31 @@ property_declaration
          CLOSE_BRACE
          {
                lbag.AppendToMember (current_property, GetLocation ($10));
+               lexer.parsing_modifiers = true;
+         }
+         opt_property_initializer
+         {
                current_property = null;
          }
        ;
 
+opt_property_initializer
+       : /* empty */
+       | ASSIGN
+         {
+               ++lexer.parsing_block;
+               current_local_parameters = ParametersCompiled.EmptyReadOnlyParameters;
+               start_block (GetLocation ($1));
+         }
+         expression SEMICOLON
+         {
+               --lexer.parsing_block;
+               ((Property)current_property).Initializer = (Expression) $3;
+               lbag.AppendToMember (current_property, GetLocation ($1), GetLocation ($4));
+               end_block (GetLocation ($4));
+               current_local_parameters = null;
+         }
+       ;
 
 indexer_declaration
        : opt_attributes opt_modifiers
index 4f54f268d29295abe4a7cdb611a95bb264cdce15..dbb74a7515a0d930a37c4832521afe6acb04c247 100644 (file)
@@ -139,15 +139,22 @@ namespace Mono.CSharp
                                var field = struct_info.Fields[i];
 
                                if (!fc.IsStructFieldDefinitelyAssigned (vi, field.Name)) {
-                                       if (field.MemberDefinition is Property.BackingField) {
+                                       var bf = field.MemberDefinition as Property.BackingField;
+                                       if (bf != null) {
+                                               if (bf.Initializer != null)
+                                                       continue;
+
                                                fc.Report.Error (843, loc,
                                                        "An automatically implemented property `{0}' must be fully assigned before control leaves the constructor. Consider calling the default struct contructor from a constructor initializer",
                                                        field.GetSignatureForError ());
-                                       } else {
-                                               fc.Report.Error (171, loc,
-                                                       "Field `{0}' must be fully assigned before control leaves the constructor",
-                                                       field.GetSignatureForError ());
+
+                                               ok = false;
+                                               continue;
                                        }
+
+                                       fc.Report.Error (171, loc,
+                                               "Field `{0}' must be fully assigned before control leaves the constructor",
+                                               field.GetSignatureForError ());
                                        ok = false;
                                }
                        }
index 82acb67b164cd6ea51492d227ebbc34aa600f314..7336f1dbf858ade6e732cba67fd63fba724eb364 100644 (file)
@@ -721,6 +721,9 @@ namespace Mono.CSharp {
                                        if (!fs.IsPublic && container.MemberDefinition.IsImported && (!fs.MemberType.IsArray && TypeSpec.IsReferenceType (fs.MemberType)))
                                                continue;
 
+                                       //if ((fs.Modifiers & (Modifiers.BACKING_FIELD) != 0)
+                                       //      continue;
+
                                        if (fields == null)
                                                fields = new List<FieldSpec> ();
 
index e8b3879f05afb10598cf8d54e3f1d093015910c2..8c59db158bbef3448a73a468d448c23f22a930fc 100644 (file)
@@ -732,12 +732,14 @@ namespace Mono.CSharp
                {
                        readonly Property property;
 
-                       public BackingField (Property p)
+                       public BackingField (Property p, bool readOnly)
                                : base (p.Parent, p.type_expr,
                                Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | (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 {
@@ -766,6 +768,8 @@ namespace Mono.CSharp
                {
                }
 
+               public Expression Initializer { get; set; }
+
                public override void Accept (StructuralVisitor visitor)
                {
                        visitor.Visit (this);
@@ -784,10 +788,16 @@ namespace Mono.CSharp
                void CreateAutomaticProperty ()
                {
                        // Create backing field
-                       backing_field = new BackingField (this);
+                       backing_field = new BackingField (this, Initializer != null && Set == null);
                        if (!backing_field.Define ())
                                return;
 
+                       if (Initializer != null) {
+                               backing_field.Initializer = Initializer;
+                               Parent.RegisterFieldForInitialization (backing_field, new FieldInitializer (backing_field, Initializer, Location));
+                               backing_field.ModFlags |= Modifiers.READONLY;
+                       }
+
                        Parent.PartialContainer.Members.Add (backing_field);
 
                        FieldExpr fe = new FieldExpr (backing_field, Location);
@@ -802,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 ()
@@ -816,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 ();
                        }
 
diff --git a/mcs/tests/gtest-autoproperty-09.cs b/mcs/tests/gtest-autoproperty-09.cs
new file mode 100644 (file)
index 0000000..e018015
--- /dev/null
@@ -0,0 +1,52 @@
+using System;
+
+struct S
+{
+       public static int P { get; } = 4;
+
+       public static int Main ()
+       {
+               if (P != 4)
+                       return 1;
+
+               var c = new C ();
+               if (c.P != -3)
+                       return 2;
+
+               if (c.P2 != 1)
+                       return 3;
+
+               c.P2 = 9;
+               if (c.P2 != 9)
+                       return 4;
+
+               var s = new S2 (null);
+               if (s.P != 4)
+                       return 12;
+
+               if (s.P2 != 1)
+                       return 13;
+
+               s.P2 = 9;
+               if (s.P2 != 9)
+                       return 14;
+
+               return 0;
+       }
+}
+
+class C
+{
+       public decimal P { get; } = -3;
+       public int P2 { get; set; } = 1;
+}
+
+struct S2
+{
+       public int P { get; } = 4;
+       public int P2 { get; set; } = 1;
+
+       public S2 (object o)
+       {
+       }
+}
\ No newline at end of file
index a3203050ce6f31fcb502fda4886e181291196a47..df971b0e648f73c2dde03a0fed2f02868f00fc2c 100644 (file)
       </method>\r
     </type>\r
   </test>\r
+  <test name="gtest-autoproperty-09.cs">\r
+    <type name="S">\r
+      <method name="Int32 get_P()" attrs="2198">\r
+        <size>13</size>\r
+      </method>\r
+      <method name="Int32 Main()" attrs="150">\r
+        <size>192</size>\r
+      </method>\r
+      <method name="Void .cctor()" attrs="6289">\r
+        <size>7</size>\r
+      </method>\r
+    </type>\r
+    <type name="C">\r
+      <method name="System.Decimal get_P()" attrs="2182">\r
+        <size>14</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>27</size>\r
+      </method>\r
+    </type>\r
+    <type name="S2">\r
+      <method name="Int32 get_P()" attrs="2182">\r
+        <size>14</size>\r
+      </method>\r
+      <method name="Void .ctor(Object)" attrs="6278">\r
+        <size>16</size>\r
+      </method>\r
+    </type>\r
+    <type name="C">\r
+      <method name="Int32 get_P2()" attrs="2182">\r
+        <size>14</size>\r
+      </method>\r
+      <method name="Void set_P2(Int32)" attrs="2182">\r
+        <size>8</size>\r
+      </method>\r
+    </type>\r
+    <type name="S2">\r
+      <method name="Int32 get_P2()" attrs="2182">\r
+        <size>14</size>\r
+      </method>\r
+      <method name="Void set_P2(Int32)" attrs="2182">\r
+        <size>8</size>\r
+      </method>\r
+    </type>\r
+  </test>\r
   <test name="gtest-collectioninit-01.cs">\r
     <type name="Test">\r
       <method name="Void TestList(System.Collections.Generic.List`1[System.Int32], Int32)" attrs="145">\r