[mcs] Add dictionary initializer
authorMarek Safar <marek.safar@gmail.com>
Fri, 15 Aug 2014 18:43:03 +0000 (20:43 +0200)
committerMarek Safar <marek.safar@gmail.com>
Fri, 15 Aug 2014 18:51:18 +0000 (20:51 +0200)
mcs/errors/cs0021-5.cs [new file with mode: 0644]
mcs/errors/cs1644-44.cs [new file with mode: 0644]
mcs/errors/cs8074.cs [new file with mode: 0644]
mcs/mcs/cs-parser.jay
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/tests/test-dictinit-01.cs [new file with mode: 0644]
mcs/tests/test-dictinit-02.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_5.xml

diff --git a/mcs/errors/cs0021-5.cs b/mcs/errors/cs0021-5.cs
new file mode 100644 (file)
index 0000000..19c4483
--- /dev/null
@@ -0,0 +1,12 @@
+// CS0021: Cannot apply indexing with [] to an expression of type `object'
+// Line: 9
+
+class C
+{
+       public static void Main ()
+       {
+               var d = new object {
+                       ["a"] = 1
+               };
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs1644-44.cs b/mcs/errors/cs1644-44.cs
new file mode 100644 (file)
index 0000000..80013d3
--- /dev/null
@@ -0,0 +1,15 @@
+// CS1644: Feature `dictionary initializer' cannot be used because it is not part of the C# 5.0 language specification
+// Line: 12
+// Compiler options: -langversion:5
+
+using System.Collections.Generic;
+
+class C
+{
+       public static void Main ()
+       {
+               var d = new Dictionary<string, int> {
+                       ["a"] = 1
+               };
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8074.cs b/mcs/errors/cs8074.cs
new file mode 100644 (file)
index 0000000..25d4e81
--- /dev/null
@@ -0,0 +1,16 @@
+// CS8074: Expression tree cannot contain a dictionary initializer
+// Line: 13
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+class C
+{
+       public static void Main ()
+       {
+               Expression<Func<Dictionary<string, int>>> l = () => new Dictionary<string, int> {
+                       ["a"] = 1
+               };
+       }
+}
\ No newline at end of file
index 079a5673a0832e5208b425dd2f63c81d89e442b1..2bb463413613a1ca011a9501051c24d7e6365c1d 100644 (file)
@@ -3485,7 +3485,15 @@ member_initializer
                else
                        $$ = new CollectionElementInitializer ((List<Expression>)$2, GetLocation ($1));
 
-               lbag.AddLocation ($$, GetLocation ($2));
+               lbag.AddLocation ($$, GetLocation ($3));
+         }
+       | OPEN_BRACKET_EXPR expression_list CLOSE_BRACKET ASSIGN initializer_value
+         {
+               if (lang_version < LanguageVersion.V_6)
+                       FeatureIsNotAvailable (GetLocation ($1), "dictionary initializer");
+
+               $$ = new DictionaryElementInitializer ((List<Expression>)$2, (Expression) $5, GetLocation ($1));
+               lbag.AddLocation ($$, GetLocation ($3), GetLocation ($4));
          }
        | OPEN_BRACE CLOSE_BRACE
          {
index 576634fad8fae8ba38eac4fe7c8f7b86ab3b39ce..db99cf9dc4b3441f8255f236097303e2ff06f72b 100644 (file)
@@ -766,6 +766,9 @@ namespace Mono.CSharp {
                                        break;
                                case MemberKind.MissingType:
                                case MemberKind.InternalCompilerType:
+// LAMESPEC: dynamic is not really object
+//                                     if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
+//                                             goto default;
                                        break;
                                default:
                                        rc.Report.SymbolRelatedToPreviousError (type);
index afaa5c6666cc7f1cd57049d2f8875d1981581cb2..2c82ca1e443e52873120818ce46b65763c78fef4 100644 (file)
@@ -9482,10 +9482,7 @@ namespace Mono.CSharp
                                return indexer;
                        }
 
-                       if (type != InternalType.ErrorType) {
-                               ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
-                                       type.GetSignatureForError ());
-                       }
+                       Error_CannotApplyIndexing (ec, type, loc);
 
                        return null;
                }
@@ -9498,6 +9495,14 @@ namespace Mono.CSharp
                        return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
                }
 
+               public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
+               {
+                       if (type != InternalType.ErrorType) {
+                               rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
+                                       type.GetSignatureForError ());
+                       }
+               }
+
                public override bool HasConditionalAccess ()
                {
                        return ConditionalAccess || Expr.HasConditionalAccess ();
@@ -9864,19 +9869,24 @@ namespace Mono.CSharp
        //
        // Indexer access expression
        //
-       sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
+       class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
        {
                IList<MemberSpec> indexers;
                Arguments arguments;
                TypeSpec queried_type;
                
                public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
-                       : base (ea.Location)
+                       : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
+               {
+               }
+
+               public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
+                       : base (loc)
                {
                        this.indexers = indexers;
                        this.queried_type = queriedType;
-                       this.InstanceExpression = ea.Expr;
-                       this.arguments = ea.Arguments;
+                       this.InstanceExpression = instance;
+                       this.arguments = args;
                }
 
                #region Properties
@@ -10801,6 +10811,12 @@ namespace Mono.CSharp
                {
                        this.Name = name;
                }
+
+               public bool IsDictionaryInitializer {
+                       get {
+                               return Name == null;
+                       }
+               }
                
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
@@ -10837,72 +10853,80 @@ namespace Mono.CSharp
                        if (source == null)
                                return EmptyExpressionStatement.Instance;
 
-                       var t = ec.CurrentInitializerVariable.Type;
+                       if (!ResolveElement (ec))
+                               return null;
+
+                       if (source is CollectionOrObjectInitializers) {
+                               Expression previous = ec.CurrentInitializerVariable;
+                               ec.CurrentInitializerVariable = target;
+                               source = source.Resolve (ec);
+                               ec.CurrentInitializerVariable = previous;
+                               if (source == null)
+                                       return null;
+                                       
+                               eclass = source.eclass;
+                               type = source.Type;
+                               return this;
+                       }
+
+                       return base.DoResolve (ec);
+               }
+       
+               public override void EmitStatement (EmitContext ec)
+               {
+                       if (source is CollectionOrObjectInitializers)
+                               source.Emit (ec);
+                       else
+                               base.EmitStatement (ec);
+               }
+
+               protected virtual bool ResolveElement (ResolveContext rc)
+               {
+                       var t = rc.CurrentInitializerVariable.Type;
                        if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
                                Arguments args = new Arguments (1);
-                               args.Add (new Argument (ec.CurrentInitializerVariable));
+                               args.Add (new Argument (rc.CurrentInitializerVariable));
                                target = new DynamicMemberBinder (Name, args, loc);
                        } else {
 
-                               var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
+                               var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
                                if (member == null) {
-                                       member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
+                                       member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
 
                                        if (member != null) {
                                                // TODO: ec.Report.SymbolRelatedToPreviousError (member);
-                                               ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
-                                               return null;
+                                               ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
+                                               return false;
                                        }
                                }
 
                                if (member == null) {
-                                       Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
-                                       return null;
+                                       Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
+                                       return false;
                                }
 
                                var me = member as MemberExpr;
                                if (me is EventExpr) {
-                                       me = me.ResolveMemberAccess (ec, null, null);
+                                       me = me.ResolveMemberAccess (rc, null, null);
                                } else if (!(member is PropertyExpr || member is FieldExpr)) {
-                                       ec.Report.Error (1913, loc,
+                                       rc.Report.Error (1913, loc,
                                                "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
                                                member.GetSignatureForError ());
 
-                                       return null;
+                                       return false;
                                }
 
                                if (me.IsStatic) {
-                                       ec.Report.Error (1914, loc,
+                                       rc.Report.Error (1914, loc,
                                                "Static field or property `{0}' cannot be assigned in an object initializer",
                                                me.GetSignatureForError ());
                                }
 
                                target = me;
-                               me.InstanceExpression = ec.CurrentInitializerVariable;
-                       }
-
-                       if (source is CollectionOrObjectInitializers) {
-                               Expression previous = ec.CurrentInitializerVariable;
-                               ec.CurrentInitializerVariable = target;
-                               source = source.Resolve (ec);
-                               ec.CurrentInitializerVariable = previous;
-                               if (source == null)
-                                       return null;
-                                       
-                               eclass = source.eclass;
-                               type = source.Type;
-                               return this;
+                               me.InstanceExpression = rc.CurrentInitializerVariable;
                        }
 
-                       return base.DoResolve (ec);
-               }
-       
-               public override void EmitStatement (EmitContext ec)
-               {
-                       if (source is CollectionOrObjectInitializers)
-                               source.Emit (ec);
-                       else
-                               base.EmitStatement (ec);
+                       return true;
                }
        }
        
@@ -10985,6 +11009,40 @@ namespace Mono.CSharp
                        return base.DoResolve (ec);
                }
        }
+
+       class DictionaryElementInitializer : ElementInitializer
+       {
+               readonly Arguments args;
+
+               public DictionaryElementInitializer (List<Expression> arguments, Expression initializer, Location loc)
+                       : base (null, initializer, loc)
+               {
+                       this.args = new Arguments (arguments.Count);
+                       foreach (var arg in arguments)
+                               this.args.Add (new Argument (arg));
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext ec)
+               {
+                       ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
+                       return null;
+               }
+
+               protected override bool ResolveElement (ResolveContext rc)
+               {
+                       var init = rc.CurrentInitializerVariable;
+                       var type = init.Type;
+
+                       var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
+                       if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
+                               ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
+                               return false;
+                       }
+
+                       target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
+                       return true;
+               }
+       }
        
        //
        // A block of object or collection initializers
@@ -11072,8 +11130,9 @@ namespace Mono.CSharp
                                if (i == 0) {
                                        if (element_initializer != null) {
                                                element_names = new List<string> (initializers.Count);
-                                               element_names.Add (element_initializer.Name);
-                                       } else if (initializer is CompletingExpression){
+                                               if (!element_initializer.IsDictionaryInitializer)
+                                                       element_names.Add (element_initializer.Name);
+                                       } else if (initializer is CompletingExpression) {
                                                initializer.Resolve (ec);
                                                throw new InternalErrorException ("This line should never be reached");
                                        } else {
@@ -11096,7 +11155,7 @@ namespace Mono.CSharp
                                                continue;
                                        }
 
-                                       if (!is_collection_initialization) {
+                                       if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
                                                if (element_names.Contains (element_initializer.Name)) {
                                                        ec.Report.Error (1912, element_initializer.Location,
                                                                "An object initializer includes more than one member `{0}' initialization",
diff --git a/mcs/tests/test-dictinit-01.cs b/mcs/tests/test-dictinit-01.cs
new file mode 100644 (file)
index 0000000..1944ae8
--- /dev/null
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+
+class Program
+{
+       static int Main ()
+       {
+               var c1 = new C {
+                       ["aaa"] = 12,
+               };
+
+               if (c1.Dict ["aaa"] != 12)
+                       return 1;
+
+               var c2 = new C {
+                       ["a1"] = 5,
+                       ["a2"] = 10,
+                       Value = 20,
+               };
+
+               if (c2.Dict ["a1"] != 5)
+                       return 2;
+
+               if (c2.Dict ["a2"] != 10)
+                       return 3;
+
+               if (c2.Value != 20)
+                       return 4;
+
+               return 0;
+       }
+}
+
+
+class C
+{
+       public Dictionary<string, int> Dict = new Dictionary<string, int> ();
+
+       public int Value;
+
+       public int this [string arg] {
+               get {
+                       return Dict [arg];
+               }
+               set {
+                       Dict [arg] = value;
+               }
+       }
+}
\ No newline at end of file
diff --git a/mcs/tests/test-dictinit-02.cs b/mcs/tests/test-dictinit-02.cs
new file mode 100644 (file)
index 0000000..ecd59da
--- /dev/null
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+
+class Program
+{
+       static int Main ()
+       {
+               var c = new C {
+                       ["l1"] = new C {
+                               ["l2"] = new C () {
+                                       Value = 10
+                               }
+                       },
+                       ["l5"] = {
+                               ["51"] = new C () {
+                                       Value = 100
+                               }
+                       }
+               };
+
+               if (c ["l1"]["l2"].Value != 10)
+                       return 1;
+
+               if (c ["l5"]["51"].Value != 100)
+                       return 2;
+
+               return 0;
+       }
+}
+
+
+class C
+{
+       public Dictionary<string, C> Dict = new Dictionary<string, C> ();
+
+       public int Value;
+
+       public C this [string arg] {
+               get {
+                       C c;
+                       if (!Dict.TryGetValue (arg, out c)) {
+                               c = new C ();
+                               Dict [arg] = c;
+                       }
+
+                       return c;
+               }
+               set {
+                       Dict [arg] = value;
+               }
+       }
+}
\ No newline at end of file
index e16b93b0f47f2cbd140e0ae5548db39cb2314f95..562d4d6fa544bb2dd7ecccd76c2db368787e37ba 100644 (file)
       </method>\r
     </type>\r
   </test>\r
+  <test name="test-dictinit-01.cs">\r
+    <type name="Program">\r
+      <method name="Int32 Main()" attrs="145">\r
+        <size>181</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>7</size>\r
+      </method>\r
+    </type>\r
+    <type name="C">\r
+      <method name="Int32 get_Item(System.String)" attrs="2182">\r
+        <size>21</size>\r
+      </method>\r
+      <method name="Void set_Item(System.String, Int32)" attrs="2182">\r
+        <size>15</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>18</size>\r
+      </method>\r
+    </type>\r
+  </test>\r
+  <test name="test-dictinit-02.cs">\r
+    <type name="Program">\r
+      <method name="Int32 Main()" attrs="145">\r
+        <size>182</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>7</size>\r
+      </method>\r
+    </type>\r
+    <type name="C">\r
+      <method name="C get_Item(System.String)" attrs="2182">\r
+        <size>50</size>\r
+      </method>\r
+      <method name="Void set_Item(System.String, C)" attrs="2182">\r
+        <size>15</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>18</size>\r
+      </method>\r
+    </type>\r
+  </test>\r
+  <test name="test-dictinit-03.cs">\r
+    <type name="Program">\r
+      <method name="Int32 Main()" attrs="145">\r
+        <size>196</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>7</size>\r
+      </method>\r
+    </type>\r
+    <type name="C">\r
+      <method name="System.Object get_Item(System.String)" attrs="2182">\r
+        <size>26</size>\r
+      </method>\r
+      <method name="Void set_Item(System.String, System.Object)" attrs="2182">\r
+        <size>81</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>18</size>\r
+      </method>\r
+    </type>\r
+  </test>\r
   <test name="test-ex-filter-01.cs">\r
     <type name="X">\r
       <method name="Int32 Main()" attrs="150">\r